<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Guido Zambarda</title>
    <description>The latest articles on Forem by Guido Zambarda (@guidozam).</description>
    <link>https://forem.com/guidozam</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1228379%2F9a604eff-a326-40fa-87d6-07caa19af80c.jpeg</url>
      <title>Forem: Guido Zambarda</title>
      <link>https://forem.com/guidozam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/guidozam"/>
    <language>en</language>
    <item>
      <title>VSCode extension – Node version pal</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Tue, 05 May 2026 09:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/vscode-extension-node-version-pal-3779</link>
      <guid>https://forem.com/guidozam/vscode-extension-node-version-pal-3779</guid>
      <description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;If you’re working across multiple Node.js projects, you already know the struggle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One project requires Node 16&lt;/li&gt;



&lt;li&gt;Another depends on Node 18&lt;/li&gt;



&lt;li&gt;A legacy service still runs on Node 14&lt;/li&gt;



&lt;li&gt;And somehow your terminal is on the wrong version… again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s exactly why &lt;strong&gt;Node Version Pal&lt;/strong&gt; was created.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node Version Pal&lt;/strong&gt; is a lightweight Visual Studio Code extension that detects, displays, and helps you switch your project’s Node.js version — directly from the VSCode status bar.&lt;/p&gt;

&lt;p&gt;No more guessing. No more terminal checks. No more “why is this build failing?”&lt;/p&gt;




&lt;h2&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f4a1.png" alt="💡" width="72" height="72"&gt; What Problem Does It Solve?&lt;/h2&gt;

&lt;p&gt;Modern JavaScript development often means juggling multiple repositories — each with its own required Node version defined (hopefully) in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.nvmrc&lt;/code&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;.node-version&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Forgetting to switch versions can lead to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build errors&lt;/li&gt;



&lt;li&gt;Runtime incompatibilities&lt;/li&gt;



&lt;li&gt;Dependency installation issues&lt;/li&gt;



&lt;li&gt;Subtle bugs that waste hours&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Node Version Pal makes your Node version &lt;strong&gt;visible, accurate, and manageable — right inside your editor.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F2728.png" alt="✨" width="72" height="72"&gt; Key Features&lt;/h2&gt;

&lt;h3&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f50d.png" alt="🔍" width="72" height="72"&gt; Automatic Version Detection&lt;/h3&gt;

&lt;p&gt;Open a project containing a &lt;code&gt;.nvmrc&lt;/code&gt; or &lt;code&gt;.node-version&lt;/code&gt; file and Node Version Pal instantly detects the required Node version — no setup required.&lt;/p&gt;

&lt;p&gt;It works quietly in the background and keeps your workflow uninterrupted.&lt;/p&gt;




&lt;h3&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f4ca.png" alt="📊" width="72" height="72"&gt; Node Version in the Status Bar&lt;/h3&gt;

&lt;p&gt;Your project’s required Node version appears directly in the VS Code status bar.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You always know which version your project expects&lt;/li&gt;



&lt;li&gt;You can instantly spot mismatches&lt;/li&gt;



&lt;li&gt;No need to open a terminal to check &lt;code&gt;node -v&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clear. Simple. Reliable.&lt;/p&gt;




&lt;h3&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F26a1.png" alt="⚡" width="72" height="72"&gt; One-Click Version Switching&lt;/h3&gt;

&lt;p&gt;Click the status bar item to switch Node versions using your installed version manager (like &lt;code&gt;nvm&lt;/code&gt; or &lt;code&gt;fnm&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;No need to type commands.&lt;br&gt;No need to remember version numbers.&lt;br&gt;Just click and switch.&lt;/p&gt;




&lt;h3&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f504.png" alt="🔄" width="72" height="72"&gt; Auto-Refresh When You Change Branches&lt;/h3&gt;

&lt;p&gt;Switch Git branches?&lt;br&gt;Pull changes?&lt;br&gt;Update your &lt;code&gt;.nvmrc&lt;/code&gt; file?&lt;/p&gt;

&lt;p&gt;Node Version Pal automatically refreshes and updates the displayed version — so you’re never out of sync.&lt;/p&gt;




&lt;h3&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f4c1.png" alt="📁" width="72" height="72"&gt; Multi-Workspace Support&lt;/h3&gt;

&lt;p&gt;Working with multi-root workspaces or microservices?&lt;/p&gt;

&lt;p&gt;Each workspace folder is scanned independently, so every project shows the correct Node version for its context.&lt;/p&gt;

&lt;p&gt;Perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monorepos&lt;/li&gt;



&lt;li&gt;Microservices&lt;/li&gt;



&lt;li&gt;Full-stack setups&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F2795.png" alt="➕" width="72" height="72"&gt; Create Version Files Easily&lt;/h3&gt;

&lt;p&gt;Don’t have a &lt;code&gt;.nvmrc&lt;/code&gt; yet?&lt;/p&gt;

&lt;p&gt;Node Version Pal allows you to quickly create one directly from VS Code — helping you standardize your project setup and improve team consistency.&lt;/p&gt;




&lt;h2&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f3af.png" alt="🎯" width="72" height="72"&gt; Why Developers Love It&lt;/h2&gt;

&lt;p&gt;Node Version Pal is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lightweight&lt;/li&gt;



&lt;li&gt;Non-intrusive&lt;/li&gt;



&lt;li&gt;Zero-configuration&lt;/li&gt;



&lt;li&gt;Focused on developer productivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It doesn’t try to replace your version manager.&lt;br&gt;It enhances your workflow by making Node version awareness effortless.&lt;/p&gt;

&lt;p&gt;If you work with Node daily, this extension becomes one of those tools you don’t want to live without.&lt;/p&gt;




&lt;h2&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f4e6.png" alt="📦" width="72" height="72"&gt; How to Install&lt;/h2&gt;

&lt;p&gt;Installing Node Version Pal takes less than a minute:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Visual Studio Code&lt;/strong&gt;
&lt;/li&gt;



&lt;li&gt;Go to the Extensions panel (&lt;code&gt;Ctrl+Shift+X&lt;/code&gt; / &lt;code&gt;Cmd+Shift+X&lt;/code&gt;)&lt;/li&gt;



&lt;li&gt;Search for &lt;strong&gt;Node Version Pal&lt;/strong&gt;
&lt;/li&gt;



&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or install directly from the Visual Studio Code Marketplace:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f449.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f449.png" alt="👉" width="72" height="72"&gt;&lt;/a&gt; &lt;a href="https://marketplace.visualstudio.com/items?itemName=guidozam.vscode-node-version-pal&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=guidozam.vscode-node-version-pal&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs0.wp.com%2Fwp-content%2Fmu-plugins%2Fwpcom-smileys%2Ftwemoji%2F2%2F72x72%2F1f680.png" alt="🚀" width="72" height="72"&gt; Final Thoughts&lt;/h2&gt;

&lt;p&gt;Small tools can make a huge difference in daily development.&lt;/p&gt;

&lt;p&gt;Node Version Pal removes friction, prevents mistakes, and keeps your environment aligned with your project — all without leaving your editor.&lt;/p&gt;

&lt;p&gt;If you’re juggling Node versions across projects, give it a try today.&lt;/p&gt;

&lt;p&gt;Your future self (and your builds) will thank you.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>developertool</category>
      <category>vscode</category>
      <category>extension</category>
    </item>
    <item>
      <title>Cannot turn on Power Automate flow: [REDACTED] error</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 29 Apr 2026 09:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/cannot-turn-on-power-automate-flow-redacted-error-847</link>
      <guid>https://forem.com/guidozam/cannot-turn-on-power-automate-flow-redacted-error-847</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Lately I ran into an issue with a Power Automate flow. After exporting a solution with a specific flow to a different environment, I am facing an issue where the flow, which was running fine in the original environment, is turned off. When I try to turn on the flow I get the following error message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs58jc8djbc0uaityzf23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs58jc8djbc0uaityzf23.png" alt="[REDACTED]" width="112" height="37"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[REDACTED]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which, I think everyone can agree, is not a very useful message.&lt;/p&gt;

&lt;p&gt;Due to the very obscure meaning of the message, I’ve tried opening the flow and saving it, this triggered the following error message:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hgo4im8i7qadpvakbzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4hgo4im8i7qadpvakbzd.png" alt="Request to XRM API failed with error: 'Message: Flow client error returned with status code " width="800" height="33"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Request to XRM API failed with error: ‘Message: Flow client error returned with status code “BadRequest” and details “InvalidOpenApiFlow”. Code: 0x80060467 InnerError: ‘.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which can point to some direction, but it’s not a very helpful message…and, in all of this, the flow checker gives no errors!&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;At least in my case, scrolling through the actions, I discovered that an action was in error.&lt;/p&gt;

&lt;p&gt;Following you can see the error in the old designer, which was not visible until I’ve expanded the action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvls8dx0ko4i0gjv8rwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvls8dx0ko4i0gjv8rwp.png" alt="The dynamic operation request to API 'wordonlinebusiness' operation 'GetFileSchema' failed with status code 'NotFound'. This may indicate invalid input parameters. Error response: { " width="551" height="157"&gt;&lt;/a&gt;", "error": { "message": "The selected file doesn't exist, please select a valid file and drive." }, "source": "wordonlinebusiness-we.azconn-we-003.p.azurewebsites.net" }"/&amp;gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The dynamic operation request to API ‘wordonlinebusiness’ operation ‘GetFileSchema’ failed with status code ‘NotFound’. This may indicate invalid input parameters. Error response: { “status”: 404, “message”: “The selected file doesn’t exist, please select a valid file and drive. clientRequestId: ”, “error”: { “message”: “The selected file doesn’t exist, please select a valid file and drive.” }, “source”: “wordonlinebusiness-we.azconn-we-003.p.azurewebsites.net” }&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The same error is present switching to the new designer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5ao84ocw4l0gkedp2at.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn5ao84ocw4l0gkedp2at.png" width="325" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At least in the new designer the error was already visible without having to expand the action content.&lt;/p&gt;

&lt;p&gt;So, what was the solution?&lt;/p&gt;

&lt;p&gt;It simply was to &lt;strong&gt;update the selected document in the Word Business action&lt;/strong&gt; , simply as that!&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>powerplatform</category>
      <category>errors</category>
      <category>flow</category>
    </item>
    <item>
      <title>Enable SharePoint AI on your tenant (preview)</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 22 Apr 2026 09:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/enable-sharepoint-ai-on-your-tenant-preview-3c72</link>
      <guid>https://forem.com/guidozam/enable-sharepoint-ai-on-your-tenant-preview-3c72</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3ejzcctpyfk5a8kg0l1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw3ejzcctpyfk5a8kg0l1.png" alt="⚠" width="72" height="72"&gt;&lt;/a&gt; This feature is in preview at the time of writing&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Artificial Intelligence is no longer a future capability in SharePoint—it’s already here, and it’s deeply integrated with the modern Microsoft 365 experience. With the introduction of &lt;em&gt;Knowledge Agents&lt;/em&gt;, organisations can unlock contextual insights, automate knowledge discovery, and dramatically improve how users interact with content.&lt;/p&gt;

&lt;p&gt;In this post, we’ll walk through how to enable SharePoint AI on your tenant and what prerequisites you need.&lt;/p&gt;

&lt;p&gt;Before covering the required steps, let me briefly cover what SharePoint AI enables on SPO. It introduces intelligent agents that can understand and interact with your content. These agents can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Answer questions based on SharePoint Online sites and documents&lt;/li&gt;
&lt;li&gt;Summarize pages and libraries&lt;/li&gt;
&lt;li&gt;Assist users with contextual knowledge retrieval&lt;/li&gt;
&lt;li&gt;Allow AI assisted document library column generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each SharePoint Online site even comes with a ready-made agent scoped to its content, and you can also build custom agents tailored to specific business needs!&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To enable SharePoint AI on your tenant there are three main prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft 365 Copilot license: users must have an active license to use AI capabilities in SharePoint Online.&lt;/li&gt;
&lt;li&gt;At the moment, the tenant must be opted-in in order to enable the AI capabilities, by default this is disabled.&lt;/li&gt;
&lt;li&gt;Enable Anthropic as AI provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;p&gt;Starting from a newly created SharePoint Online site, you can see that there is nothing regarding AI in here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv8gf7w13rgf5gvpus2g3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv8gf7w13rgf5gvpus2g3.png" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To enable AI features, you will first need to opt-in as currently the option is turned off on all tenants. To do that you will need a SharePoint Administrator or a Global Administrator to execute a PowerShell command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Opt-in to AI in SharePoint Online
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: use Windows PowerShell for the following operations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to opt-in you will first need to install or update the module: &lt;code&gt;Microsoft.Online.SharePoint.PowerShell&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After installation, you can use the module to perform the opt-in for all sites or for specific sites.&lt;/p&gt;

&lt;p&gt;To execute the following commands, you will need to first connect to the SharePoint admin URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Connect-SPOService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://yourtenant-admin.sharepoint.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Enable for all sites
&lt;/h4&gt;

&lt;p&gt;To opt-in for all sites you have in your SharePoint tenant you can execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-SPOTenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-KnowledgeAgentScope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;AllSites&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After executing the above command, you can check the configuration of the tenant running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-SPOTenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KnowledgeAgentScope&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Enable for selected sites
&lt;/h4&gt;

&lt;p&gt;To enable SharePoint AI for a selected site, you can set the &lt;code&gt;KnowledgeAgentScope&lt;/code&gt; to include the sites from a list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-SPOTenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-KnowledgeAgentScope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IncludeSelectedSites&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To specify the sites to be included you can set the &lt;code&gt;KnowledgeAgentSelectedSitesList&lt;/code&gt; parameter, in the following code example I am adding two different sites to the list of sites that will opt-in to SharePoint AI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-SPOTenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-KnowledgeAgentSelectedSitesList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"https://yourtenant.sharepoint.com/sites/AwesomeSite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://yourtenant.sharepoint.com/sites/sampleSite02"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already executed the above command and need to append another site to the list of sites, you can set the &lt;code&gt;KnowledgeAgentSelectedSitesListOperation&lt;/code&gt; parameter with the &lt;code&gt;Append&lt;/code&gt; operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-SPOTenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-KnowledgeAgentSelectedSitesList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"https://yourtenant.sharepoint.com/sites/NewSite"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-KnowledgeAgentSelectedSitesListOperation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Append&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, if you need to check that the values are correctly updated, you can execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-SPOTenant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KnowledgeAgentScope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KnowledgeAgentSelectedSitesList&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enable Anthropic AI provider
&lt;/h3&gt;

&lt;p&gt;As last step, you need to enable Anthropic as Microsoft subprocessor.&lt;/p&gt;

&lt;p&gt;To do that, navigate to the &lt;strong&gt;Microsoft 365 admin center&lt;/strong&gt; , open the &lt;strong&gt;Copilot&lt;/strong&gt; section on the left, and then select &lt;strong&gt;Connectors&lt;/strong&gt; , from here select the &lt;strong&gt;AI providers operating as Microsoft subprocessors&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fay1917wwsax13qau9tza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fay1917wwsax13qau9tza.png" width="800" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A panel will open on the right side of the page, where you can select &lt;strong&gt;Anthropic&lt;/strong&gt; as the available subprocessor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4pf7d9gv5t1i63rlnyl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4pf7d9gv5t1i63rlnyl.png" width="800" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Enjoy!
&lt;/h3&gt;

&lt;p&gt;After performing the above tasks, if you return to the site (or sites) for which you have opted-in, you will see a new icon in the bottom right corner of the page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7y9s2eheq48z7uph6r8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7y9s2eheq48z7uph6r8.png" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the new button you can perform multiple operations, to have an idea here is the menu and the various options available:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tqyvuo0pwkb1gs14tqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2tqyvuo0pwkb1gs14tqw.png" width="364" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I won’t cover all the options in this blog post as it is focused only on how to enable SharePoint AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;If you want to know more about how to get started with AI in SharePoint, have a look at the official documentation &lt;a href="https://learn.microsoft.com/en-us/sharepoint/knowledge-agent-get-started" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;AI in SharePoint is a very nice usage of AI, it allows various features that are quite powerful for users, if you want to know more about the capabilities have a look &lt;a href="https://support.microsoft.com/en-us/topic/ai-in-sharepoint-an-overview-c0b1efc3-81d0-4981-8be9-7ba3a75fae15" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>sharepoint</category>
    </item>
    <item>
      <title>VSCode extension – SPFx version pal</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Tue, 21 Apr 2026 09:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/vscode-extension-spfx-version-pal-5hej</link>
      <guid>https://forem.com/guidozam/vscode-extension-spfx-version-pal-5hej</guid>
      <description>&lt;h2&gt;A Tiny VS Code Extension with Big SPFx Value&lt;/h2&gt;

&lt;p&gt;Working with SharePoint Framework (SPFx) projects can sometimes feel like juggling versions — especially if you’re maintaining multiple projects with different SPFx dependencies. What version of SPFx was that project using again? That’s exactly where &lt;strong&gt;SPFx Version Pal&lt;/strong&gt; comes in.&lt;/p&gt;




&lt;h3&gt;What Is SPFx Version Pal?&lt;/h3&gt;

&lt;p&gt;SPFx Version Pal is a lightweight VS Code extension that displays the detected SharePoint Framework version of your current project right in the VS Code status bar.&lt;/p&gt;

&lt;p&gt;While small in scope, it solves a very practical problem for SPFx developers — quickly identifying the framework version without digging through code or configuration files by hand.&lt;/p&gt;




&lt;h3&gt;Key Features&lt;/h3&gt;

&lt;p&gt;The power of SPFx Version Pal lies in its simplicity and unobtrusive integration with VS Code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic SPFx Project Detection&lt;/strong&gt;It scans the workspace for SPFx-related dependencies in &lt;code&gt;package.json&lt;/code&gt; — including packages like &lt;code&gt;@microsoft/sp-core-library&lt;/code&gt;, &lt;code&gt;@microsoft/sp-webpart-base&lt;/code&gt;, and others — to determine the SPFx version.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Version Display in the Status Bar&lt;/strong&gt;Once detected, the SPFx version is shown in the status bar — so you always know which version you’re working on at a glance.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Auto-Refresh on Changes&lt;/strong&gt;The display updates automatically when relevant parts of &lt;code&gt;package.json&lt;/code&gt; change, keeping the version indicator in sync.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Manual Refresh Option&lt;/strong&gt;You can click the status bar item or run a command from the Command Palette (&lt;code&gt;Ctrl+Shift+P&lt;/code&gt; / &lt;code&gt;Cmd+Shift+P&lt;/code&gt;) to manually refresh the version detection.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;How It Works&lt;/h3&gt;

&lt;p&gt;Under the hood, SPFx Version Pal does a simple – but effective – thing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scan the workspace&lt;/strong&gt; for &lt;code&gt;package.json&lt;/code&gt; files.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Look for SPFx dependency packages&lt;/strong&gt; that identify an SPFx project.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Extract the version&lt;/strong&gt; of the detected SPFx packages.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Display that version in the VS Code status bar&lt;/strong&gt; — always visible and always up to date as you work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach means there’s &lt;em&gt;no extra configuration&lt;/em&gt; needed — just open a project and let the extension do its thing.&lt;/p&gt;




&lt;h3&gt;Why It Matters&lt;/h3&gt;

&lt;p&gt;In real-world SPFx development, it’s incredibly common to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Switch between projects targeted at different SPFx versions.&lt;/li&gt;



&lt;li&gt;Join a team mid-project and need quick context.&lt;/li&gt;



&lt;li&gt;Tackle legacy code that hasn’t been updated in a while.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without SPFx Version Pal, you’d typically have to open and read the &lt;code&gt;package.json&lt;/code&gt;, search for SPFx packages, and interpret version strings manually. That might only take a minute — but &lt;em&gt;minutes add up&lt;/em&gt;, and context matters when you’re deep in development mode. SPFx Version Pal removes that friction by keeping version info right where you look most.&lt;/p&gt;




&lt;h3&gt;Who Should Use It?&lt;/h3&gt;

&lt;p&gt;This extension is perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SharePoint developers working with SPFx projects in VS Code.&lt;/li&gt;



&lt;li&gt;Teams managing multiple SPFx solutions over time.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;Installation &amp;amp; Requirements&lt;/h3&gt;

&lt;p&gt;To use SPFx Version Pal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need Visual Studio Code.&lt;/li&gt;



&lt;li&gt;Open any SPFx project with a valid &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;



&lt;li&gt;The extension will automatically detect and display the version in the status bar after installation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Installation is straightforward — just install it from the VSCode extension marketplace, you can see it from the link: &lt;a href="https://marketplace.visualstudio.com/items?itemName=guidozam.vscode-spfx-version-pal" rel="noopener noreferrer"&gt;SPFx version pal&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;SPFx Version Pal is a &lt;em&gt;simple but smart&lt;/em&gt; productivity boost — a little helper that gives you constant visibility into your SPFx version context without having to hunt through files. It’s a great example of how focused tooling can make a developer’s routine workflow smoother and less error-prone.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>extension</category>
    </item>
    <item>
      <title>Discover the ComboBoxListItemPicker control from the PnP reusable React controls</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 08 Apr 2026 09:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/discover-the-comboboxlistitempicker-control-from-the-pnp-reusable-react-controls-ioj</link>
      <guid>https://forem.com/guidozam/discover-the-comboboxlistitempicker-control-from-the-pnp-reusable-react-controls-ioj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Continuing our exploration of the PnP React controls, today I want to talk about the &lt;code&gt;ComboBoxListItemPicker&lt;/code&gt; control, a powerful component that combines the functionality of a combobox with SharePoint list item selection capabilities.&lt;/p&gt;

&lt;p&gt;If you’re interested, you can find the code of this sample &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/pnp-react-controls/pnp-checkbox-list-item-picker" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ComboBoxListItemPicker&lt;/code&gt; control allows users to select one or more items from a SharePoint list using a combobox interface. The control provides a list of options, suggestions based on user input and supports various configuration options for filtering, ordering, and customization.&lt;/p&gt;

&lt;p&gt;This control is particularly useful when you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow users to select items from large SharePoint lists&lt;/li&gt;
&lt;li&gt;Filter list items based on specific criteria&lt;/li&gt;
&lt;li&gt;Support both single and multiple item selection&lt;/li&gt;
&lt;li&gt;Integrate seamlessly with SharePoint Online environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Visual appearance
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ComboBoxListItemPicker&lt;/code&gt; control offers a wide range of configuration options. Let me showcase some of the various features and functionalities available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Single Selection
&lt;/h3&gt;

&lt;p&gt;Starting with the minimal configuration, this is how the control appears with basic single-item selection:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ar6ypauc4hhl526koph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ar6ypauc4hhl526koph.png" width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The control displays a clean combobox interface to select the item(s) needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gaj8bcesf3msg592s2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gaj8bcesf3msg592s2c.png" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once selected an item(s) it will be displayed in the control as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0ubna0uv9vh32bbsm1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0ubna0uv9vh32bbsm1j.png" width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Multiple Selection Mode
&lt;/h3&gt;

&lt;p&gt;When configured for multiple selections, the control allows users to select several items from the list:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpk9r5q22x2kro7llu3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpk9r5q22x2kro7llu3s.png" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selected items are displayed inside the control, and users can easily remove them by deselecting those from the dropdown options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4lcx6d3js9aojq63h9v8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4lcx6d3js9aojq63h9v8.png" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Filtered Results
&lt;/h3&gt;

&lt;p&gt;The control supports OData filtering to show only specific items that match certain criteria:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fweaydt2lk42prr9tzuyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fweaydt2lk42prr9tzuyh.png" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, the filter is applied to show only items with the word “different” in the title, demonstrating how you can programmatically restrict the available options based on your requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default selection
&lt;/h2&gt;

&lt;p&gt;It’s possible to set programmatically the selected items so the user will find those already selected in the UI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmj77jnkxlpxohacufx7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmj77jnkxlpxohacufx7h.png" width="800" height="186"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ordered and Limited Results
&lt;/h3&gt;

&lt;p&gt;You can configure the control to show a limited number of items and order them according to specific criteria:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyhuqz16w0aplizex3ab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhyhuqz16w0aplizex3ab.png" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This example shows only the top 3 items ordered alphabetically in a descending order, which is useful for large lists where you want to show only the most relevant options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disabled State
&lt;/h3&gt;

&lt;p&gt;The control also supports a disabled state for scenarios where interaction should not be allowed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb68hsjqbvkq84x6y5l8b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb68hsjqbvkq84x6y5l8b.png" width="800" height="173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To use the PnP React controls, first you need to install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @pnp/spfx-controls-react &lt;span class="nt"&gt;--save&lt;/span&gt; &lt;span class="nt"&gt;--save-exact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the installation of the package, you can proceed with the following instructions to use the &lt;code&gt;ComboBoxListItemPicker&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;To use the control, you first need to import it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ComboBoxListItemPicker&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pnp/spfx-controls-react/lib/ListItemPicker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you understand how to install and import the component, let’s explore the different usage scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Single Selection
&lt;/h3&gt;

&lt;p&gt;The simplest implementation allows single item selection from a SharePoint list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ComboBoxListItemPicker&lt;/span&gt;
  &lt;span class="na"&gt;listId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;listId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Title'&lt;/span&gt;
  &lt;span class="na"&gt;keyColumnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'ID'&lt;/span&gt;
  &lt;span class="na"&gt;onSelectedItem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onSelectionChanged&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;webUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;absoluteUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;spHttpClient&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spHttpClient&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SelectAnItem&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;suggestionsHeaderText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AvailableItems&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;noResultsFoundText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NoItemsFound&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The required fields in order to instantiate the control are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;webUrl&lt;/code&gt;: current web URL, retrievable from the web part context.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;listId&lt;/code&gt;: the ID of the list from which the control will retrieve the items to display. In this sample, the selection of the listId value is done using the property pane with the PropertyFieldListPicker (more &lt;a href="https://iamguidozam.blog/2025/01/29/discover-how-to-use-the-propertyfieldlistpicker-from-the-pnp-property-controls/" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;columnInternalName&lt;/code&gt;: the name of the column used to display the options in the dropdown menu.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spHttpClient&lt;/code&gt;: the SharePoint HTTP client, retrievable from the web part context.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onSelectedItem&lt;/code&gt;: a function to define what happens when an item is selected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the sample, the &lt;code&gt;onSelectedItem&lt;/code&gt; property, is set to a function that handles the selection change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;_onSelectionChanged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Selected items:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;selectedItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multiple Selection Mode
&lt;/h3&gt;

&lt;p&gt;It’s possible to enable multiple selection by setting the &lt;code&gt;multiSelect&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
multiSelect={true}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full code of this instance is something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ComboBoxListItemPicker&lt;/span&gt;
  &lt;span class="na"&gt;listId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;listId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Title'&lt;/span&gt;
  &lt;span class="na"&gt;keyColumnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'ID'&lt;/span&gt;
  &lt;span class="na"&gt;onSelectedItem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onMultipleSelectionChanged&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;webUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;absoluteUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;spHttpClient&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spHttpClient&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;multiSelect&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SelectMultipleItems&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;suggestionsHeaderText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ChooseItemsMultiple&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;noResultsFoundText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NoMatchingItemsFound&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  With OData Filter
&lt;/h3&gt;

&lt;p&gt;It’s possible to apply filters to show only specific items using OData syntax. In the sample you can see that it’s using the following filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
substringof('different', Title)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, it will load all the items that have the string “different” in the title of the item.&lt;/p&gt;

&lt;p&gt;The complete code for this control instance is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ComboBoxListItemPicker&lt;/span&gt;
  &lt;span class="na"&gt;listId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;listId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Title'&lt;/span&gt;
  &lt;span class="na"&gt;keyColumnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'ID'&lt;/span&gt;
  &lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"substringof('different', Title)"&lt;/span&gt;
  &lt;span class="na"&gt;onSelectedItem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onFilteredSelectionChanged&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;webUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;absoluteUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;spHttpClient&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spHttpClient&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SelectItemsContaining&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;suggestionsHeaderText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AvailableItemsFiltered&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;noResultsFoundText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NoItemsFoundFilter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  With Default Selection
&lt;/h3&gt;

&lt;p&gt;You can provide pre-selected items using the &lt;code&gt;defaultSelectedItems&lt;/code&gt; property, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;defaultSelectedItems&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{[{&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;}]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the above code the component will be instantiated with two items selected, one with ID 1 and one with ID 3 which, in my sample, are the real IDs of the list item I have in my target SharePoint list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ComboBoxListItemPicker&lt;/span&gt;
  &lt;span class="na"&gt;listId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;listId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Title'&lt;/span&gt;
  &lt;span class="na"&gt;keyColumnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'ID'&lt;/span&gt;
  &lt;span class="na"&gt;defaultSelectedItems&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onSelectedItem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onDefaultSelectionChanged&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;webUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;absoluteUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;spHttpClient&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spHttpClient&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;multiSelect&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PreSelectedItemsExample&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;suggestionsHeaderText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ItemsPreSelected&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;noResultsFoundText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NoItemsAvailable&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The structure of the array to be set in the &lt;code&gt;defaultSelectedItems&lt;/code&gt; property can contain objects with only a property identifying the selected items.&lt;/p&gt;

&lt;h3&gt;
  
  
  With Item Limit and Ordering
&lt;/h3&gt;

&lt;p&gt;The control offers the ability to limit the number of displayed items and control their order. Here is the full control declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ComboBoxListItemPicker&lt;/span&gt;
  &lt;span class="na"&gt;listId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;listId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Title'&lt;/span&gt;
  &lt;span class="na"&gt;keyColumnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'ID'&lt;/span&gt;
  &lt;span class="na"&gt;itemLimit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Title desc'&lt;/span&gt;
  &lt;span class="na"&gt;onSelectedItem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onLimitedSelectionChanged&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;webUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;absoluteUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;spHttpClient&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spHttpClient&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LimitedSelection&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;suggestionsHeaderText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TopItemsAZ&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;noResultsFoundText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NoMatchingItemsTop5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Among the properties of the control there is the property &lt;code&gt;itemLimit&lt;/code&gt;, this property will specify how many items the control will display. In the above code the item limit is set to 3.&lt;/p&gt;

&lt;p&gt;To sort the items you can use the &lt;code&gt;orderBy&lt;/code&gt; property. This property will accept an OData sorting string, in the sample it’s using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Title desc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, of course, that’s ordering the items by title in a descending fashion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disabled State
&lt;/h3&gt;

&lt;p&gt;It’s possible to disable the control when interaction is not allowed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ComboBoxListItemPicker&lt;/span&gt;
  &lt;span class="na"&gt;listId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;listId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'Title'&lt;/span&gt;
  &lt;span class="na"&gt;keyColumnInternalName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'ID'&lt;/span&gt;
  &lt;span class="na"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onSelectedItem&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_onDisabledSelectionChanged&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;webUrl&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;absoluteUrl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;spHttpClient&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spHttpClient&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DisabledPicker&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;suggestionsHeaderText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PickerDisabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;noResultsFoundText&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PickerIsDisabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, it’s enough to set the &lt;code&gt;disabled&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt; to automatically apply a different styling and disable the possibility to interact with the control instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
disabled={true}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;In my opinion, the &lt;code&gt;ComboBoxListItemPicker&lt;/code&gt; control is an excellent solution for scenarios requiring SharePoint list item selection with a modern, user-friendly interface. It effectively combines the familiarity of a combobox with powerful SharePoint integration capabilities. The control’s support for filtering, ordering, and multiple selection modes makes it suitable for a wide range of applications.&lt;/p&gt;

&lt;p&gt;If you’re interested in learning more, you can check the official documentation &lt;a href="https://pnp.github.io/sp-dev-fx-controls-react/controls/ComboBoxListItemPicker/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>spfx</category>
      <category>pnp</category>
      <category>react</category>
    </item>
    <item>
      <title>VSCode extension – Invisifolder</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Tue, 07 Apr 2026 09:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/vscode-extension-invisifolder-3me4</link>
      <guid>https://forem.com/guidozam/vscode-extension-invisifolder-3me4</guid>
      <description>&lt;h2&gt;
  
  
  Clean Up Your VS Code Explorer with One Click
&lt;/h2&gt;

&lt;p&gt;If you’re like most developers, your Visual Studio Code workspace can quickly become cluttered with generated folders, build artifacts, and other directories you don’t need to see all the time. Whether it’s &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, or dozens of other outputs, navigating around these can be a distraction — especially in large projects.&lt;/p&gt;

&lt;p&gt;That’s where  &lt;strong&gt;Invisifolder&lt;/strong&gt;  comes in: a lightweight, focused VSCode extension that helps you  &lt;strong&gt;hide and manage folders&lt;/strong&gt; right from the editor. It lets you reclaim your Explorer view and focus on the files that matter most.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Invisifolder Does
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Invisifolder&lt;/strong&gt;  is a free extension for Visual Studio Code that helps you  &lt;strong&gt;hide selected folders&lt;/strong&gt;  from the Explorer view to keep your workspace clean and distraction-free. Instead of manually editing your &lt;code&gt;settings.json&lt;/code&gt; or adding complex patterns to your &lt;code&gt;files.exclude&lt;/code&gt;, this extension gives you an intuitive interface to  &lt;strong&gt;hide/unhide folders&lt;/strong&gt;  as you need. &lt;/p&gt;

&lt;p&gt;With Invisifolder you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hide &amp;amp; Unhide Folders Per Workspace&lt;/strong&gt;
Simply choose which folders you want out of sight — and restore them just as easily. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explorer Context Menu Integration&lt;/strong&gt;
Right-click a folder in the Explorer and choose &lt;em&gt;Hide Folder&lt;/em&gt; without touching configuration files. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Command Palette Access&lt;/strong&gt;
Use &lt;code&gt;Invisifolder: Hide Folder&lt;/code&gt; or &lt;code&gt;Invisifolder: Unhide Folder&lt;/code&gt; from the Command Palette (Ctrl/Cmd + Shift + P) to manage visibility quickly. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Status Bar Management&lt;/strong&gt;
A status bar item lets you see how many folders are hidden and manage them via a quick menu.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Settings Integration&lt;/strong&gt;
Invisifolder stores your hidden folders in your workspace’s &lt;code&gt;.vscode/settings.json&lt;/code&gt; under &lt;code&gt;"invisifolder.hiddenFolders"&lt;/code&gt; and maps them to &lt;code&gt;files.exclude&lt;/code&gt; patterns. That means even if someone else opens the project  &lt;strong&gt;without Invisifolder installed&lt;/strong&gt; , the folders stay hidden thanks to the &lt;code&gt;files.exclude&lt;/code&gt; settings. &lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Use Invisifolder
&lt;/h2&gt;

&lt;p&gt;Using Invisifolder is straightforward and intuitive:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hide a Folder&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Right-click a folder in the Explorer and select &lt;em&gt;Invisifolder: Hide Folder&lt;/em&gt;,&lt;/li&gt;
&lt;li&gt;OR open the Command Palette and run &lt;code&gt;Invisifolder: Hide Folder&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unhide a Folder&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Open the Command Palette and run &lt;code&gt;Invisifolder: Unhide Folder&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;Or manage hidden entries from the status bar. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage Your Hidden List&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Click the Invisifolder status bar icon to see all currently hidden folders and unhide one with a click. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Behind the scenes, Invisifolder keeps everything configured in your workspace settings, giving you a persistent and team-friendly way to control what shows up in the Explorer. &lt;/p&gt;




&lt;h2&gt;
  
  
  Why It Matters
&lt;/h2&gt;

&lt;p&gt;VSCode natively supports hiding files and folders using  &lt;strong&gt;&lt;code&gt;files.exclude&lt;/code&gt;&lt;/strong&gt; , but managing that manually can be tedious — especially when you want to toggle visibility frequently or per workspace. Invisifolder makes this process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast &amp;amp; interactive&lt;/strong&gt;  — No digging through JSON. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context-aware&lt;/strong&gt;  — Just right-click where you already are. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workspace-scoped&lt;/strong&gt;  — Different projects can hide different folders without global effects. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers who switch between front-end, back-end, library, and mono-repo projects, that flexibility is a game changer when managing clutter. &lt;/p&gt;




&lt;h2&gt;
  
  
  Who Should Use Invisifolder
&lt;/h2&gt;

&lt;p&gt;This extension is ideal for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers working with generated output folders (e.g., &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;out&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Anyone maintaining codebases with lots of auxiliary or tooling directories&lt;/li&gt;
&lt;li&gt;Teams who want per-workspace organization without global settings pollution&lt;/li&gt;
&lt;li&gt;VS Code users who prefer GUI controls to manual config editing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find yourself constantly editing &lt;code&gt;files.exclude&lt;/code&gt; or wish Explorer stayed focused on the files that matter, Invisifolder is a small tool with a big usability impact. &lt;/p&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You can install Invisifolder directly from the Visual Studio Code Marketplace or the Extensions view in VS Code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open VS Code&lt;/li&gt;
&lt;li&gt;Go to Extensions (Ctrl/Cmd + Shift + X)&lt;/li&gt;
&lt;li&gt;Search for  &lt;strong&gt;Invisifolder&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;em&gt;Install&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or if you prefer, here is link to VSCode marketplace: &lt;a href="https://marketplace.visualstudio.com/items?itemName=guidozam.invisifolder" rel="noopener noreferrer"&gt;Invisifolder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once installed, you’re ready to start cleaning up your workspace with just a few clicks. &lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Invisifolder might be a small utility in the grand ecosystem of VSCode extensions, but it solves a &lt;em&gt;very real&lt;/em&gt;, everyday problem in my opinion: workspace clutter and distraction. With its intuitive controls and seamless integration into Explorer, it makes folder management faster, cleaner, and less error-prone.&lt;/p&gt;

&lt;p&gt;If you crave a neat, efficient workspace — this extension is worth a try!&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>extension</category>
    </item>
    <item>
      <title>Discover the ListItemComment control from the PnP reusable React controls</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 25 Mar 2026 10:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/discover-the-listitemcomment-control-from-the-pnp-reusable-react-controls-4hg0</link>
      <guid>https://forem.com/guidozam/discover-the-listitemcomment-control-from-the-pnp-reusable-react-controls-4hg0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Proceeding with the appointments with the PnP React controls today I want to talk about the &lt;strong&gt;ListItemComment&lt;/strong&gt; control.&lt;/p&gt;

&lt;p&gt;If you’re interested you can find the code of this sample &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/pnp-react-controls/pnp-list-item-comment" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;The &lt;code&gt;ListItemComment&lt;/code&gt; control is used to add and display comments for a SharePoint list item.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual appearance
&lt;/h2&gt;

&lt;p&gt;Let’s start with the visual appearance of the sample solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvftl80a01vzsctnf8qlk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvftl80a01vzsctnf8qlk.png" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see the solution first asks for a SharePoint list in the current site.&lt;/p&gt;

&lt;p&gt;Once the list has been selected, the list items are loaded and available for selection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl39hvxzsi4vrwsz8cjhn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl39hvxzsi4vrwsz8cjhn.png" width="800" height="331"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When an item is selected, the &lt;code&gt;ListitemComment&lt;/code&gt; control will list the available comments and allow the user to insert a new comment. For example, following you can see a list item without any comment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2hcuhcvhowwbrileca6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2hcuhcvhowwbrileca6.png" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the list item has comments those are displayed in a chronological order and allow the user to perform a couple of operations such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;liking the comment&lt;/li&gt;
&lt;li&gt;deleting the comment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdi71v0v0t978owec6te.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzdi71v0v0t978owec6te.png" width="800" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s see how to use the control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To use the PnP React controls, first you need to install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; @pnp/spfx-controls-react &lt;span class="nt"&gt;--save&lt;/span&gt; &lt;span class="nt"&gt;--save-exact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the installation of the package you can proceed with the following instructions to use the &lt;strong&gt;ListItemComment&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;To use the control you first need to import it and that can be done as following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ListItemComments&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pnp/spfx-controls-react/lib/ListItemComments&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Actual implementation
&lt;/h3&gt;

&lt;p&gt;In the sample solution, a &lt;code&gt;ListPicker&lt;/code&gt; and a &lt;code&gt;ListItemPicker&lt;/code&gt; controls are used to select the actual list item to be used from the &lt;code&gt;ListItemComments&lt;/code&gt; control.&lt;/p&gt;

&lt;p&gt;Once that we have the list ID and the list item ID we can use the &lt;code&gt;ListItemComments&lt;/code&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ListItemComments&lt;/span&gt;
  &lt;span class="na"&gt;listId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedListId&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;selectedItemId&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ListItemCommentsLabel&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;serviceScope&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;serviceScope&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NB: The &lt;code&gt;context&lt;/code&gt; used for retrieving the &lt;code&gt;serviceScope&lt;/code&gt; is the web part one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ListItemComments&lt;/code&gt; control proves to be a powerful yet incredibly simple solution for integrating comment functionality into your applications. With minimal setup and a clean use, developers can quickly add robust comment handling without reinventing the wheel. It empowers developers to implement and manage comments in a flash, freeing up time to focus on building richer, more engaging user experiences.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>spfx</category>
      <category>pnp</category>
      <category>react</category>
    </item>
    <item>
      <title>Using top actions to configure web parts in a SPFx solution</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 11 Mar 2026 10:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/using-top-actions-to-configure-web-parts-in-a-spfx-solution-35hc</link>
      <guid>https://forem.com/guidozam/using-top-actions-to-configure-web-parts-in-a-spfx-solution-35hc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;With this blog post I want to cover what the top actions are and how to use those in your solution.&lt;/p&gt;

&lt;p&gt;The top actions of a web part are the commands available when you select a web part, to better understand what we are talking about, have a look at the following screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdq5r5mwq0lvn829dvu2u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdq5r5mwq0lvn829dvu2u.png" width="330" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you might not know is that it’s possible to add some customisation. The actual supported customisations are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a button.&lt;/li&gt;
&lt;li&gt;a drop down control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this sample I’ll be demonstrating how to use those two options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual appearance
&lt;/h2&gt;

&lt;p&gt;Starting with the visual appearance of the sample web part, this is how the web part renders in edit mode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F25y3ec3xozd63bhljpv6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F25y3ec3xozd63bhljpv6.png" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s zoom a little bit more on the editing toolbar:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3jzhttpfqh9in47dmxt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3jzhttpfqh9in47dmxt.png" width="594" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aside of the default buttons, you can see that there is a separator and, on the right side of it, the custom controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A like button, used to demonstrate how the control works. In this sample it will be a simple like/unlike button.&lt;/li&gt;
&lt;li&gt;A drop down control, used to specify the logging level for the web part.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After clicking on the like button, the icon will be updated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4l1chynriknssom1k8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4l1chynriknssom1k8z.png" width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me zoom in a little bit to better show you:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne8o5pg0f4nylq3z8zhr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fne8o5pg0f4nylq3z8zhr.png" width="582" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s have a quick look at the drop down:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62r0p66aoa96872o0nrn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62r0p66aoa96872o0nrn.png" width="336" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the previous screenshot you can see that there are four different logging levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Off&lt;/code&gt;: the logging is turned off and will not display anything in the browser console.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Warning&lt;/code&gt;: the logging is turned on and will only display warnings in the browser console.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Error&lt;/code&gt;: the logging is turned on and will only display errors in the browser console.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Verbose&lt;/code&gt;: the logging is turned on and will display all the logging messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqexcjevnp69a11tkuoc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzqexcjevnp69a11tkuoc.png" width="466" height="176"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faeihfnb2s3aole9awurr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faeihfnb2s3aole9awurr.png" width="652" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;p&gt;Now let’s cover the code to use the top actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisite
&lt;/h3&gt;

&lt;p&gt;The first thing, in order to use the top actions, is to install the required package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @microsoft/sp-top-actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once added the package, it’s possible to import the required types in the web part component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ITopActions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;TopActionsFieldType&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@microsoft/sp-top-actions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The types are used to define the required &lt;code&gt;getTopActionsConfiguration&lt;/code&gt; method. The &lt;code&gt;ITopActions&lt;/code&gt; is the return type of the new method, the other type is used to define the type of the action button, but we will cover that in a short while.&lt;/p&gt;

&lt;p&gt;The method has the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;getTopActionsConfiguration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;ITopActions&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;topActions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;// list of actions&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nf"&gt;onExecute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actionName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updatedValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// code to handle execution of action button&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Top action structure
&lt;/h3&gt;

&lt;p&gt;Before diving into the objects, let’s talk a little bit about the structure of the top actions.&lt;/p&gt;

&lt;p&gt;All the objects used to define a top action must have the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;type&lt;/code&gt;: is the type of the control to be displayed. This is defined using the &lt;code&gt;TopActionsFieldTyp&lt;/code&gt;e. As of now, the supported types are:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Button&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Dropdown&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;targetProperty&lt;/code&gt;: this is the name of the top action.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;properties&lt;/code&gt;: the specific properties for the selected type. Each type has a different available set of properties.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There are also some common properties that are not required. Those properties are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;title&lt;/code&gt;: the tooltip to be displayed for the control, this is also used as value for the &lt;code&gt;arial-label&lt;/code&gt; property. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shouldFocus&lt;/code&gt;: it’s a flag to specify if the control should be focused or not.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sample code
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;getTopActionsConfiguration&lt;/code&gt;, inside the &lt;code&gt;topActions&lt;/code&gt; property, you can configure the buttons that you want to be displayed.&lt;/p&gt;

&lt;p&gt;In the following snippet it’s defined the structure of the “Like” button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TopActionsFieldType.Button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;title:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strings.TopActions.ButtonTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;targetProperty:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"button"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;properties:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strings.TopActions.ButtonText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;icon:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;properties.like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"LikeSolid"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Like"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the following one, instead of the previous one, it’s defined the dropdown top action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TopActionsFieldType.Dropdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;title:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strings.TopActions.DropdownTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;targetProperty:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dropdown"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;properties:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;options:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;key:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;LoggingEnum.Off&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strings.TopActions.DropdownOptionOff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;checked:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;key:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;LoggingEnum.Warning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strings.TopActions.DropdownOptionWarning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;key:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;LoggingEnum.Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strings.TopActions.DropdownOptionError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;key:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;LoggingEnum.Verbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;strings.TopActions.DropdownOptionVerbose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The question you should be asking now it’s: ok, but how do I handle the button clicks or the dropdown option selection?&lt;/p&gt;

&lt;p&gt;This is achieved using the &lt;code&gt;onExecute&lt;/code&gt; method inside the &lt;code&gt;getTopActionsConfiguration&lt;/code&gt;method of the web part.&lt;/p&gt;

&lt;p&gt;Here is a snippet of how the &lt;code&gt;onExecute&lt;/code&gt; method can be defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;onExecute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actionName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updatedValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actionName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;like&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;like&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dropdown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;logging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;updatedValue&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;LoggingEnum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method is shared across all the top actions defined. The &lt;code&gt;actionName&lt;/code&gt; argument contains the value of the &lt;code&gt;targetProperty&lt;/code&gt;. The updatedValue will have different values based on the type of control:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Button control: the &lt;code&gt;updatedValue&lt;/code&gt; will be a boolean value set to &lt;code&gt;true&lt;/code&gt; when the button is clicked.&lt;/li&gt;
&lt;li&gt;Dropdown control: contains the &lt;code&gt;key&lt;/code&gt; value of the selected option.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;If you’re interested in knowing more you can have a look at the official documentation &lt;a href="https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/guidance/getting-started-with-top-actions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’re interested in having a look at the complete sample code you can find it &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/web%20parts/top-actions" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Top actions are an extremely useful addition to SharePoint Framework web parts, I think that many developers might be interested in using those controls and enabling different ways of interaction with the custom web parts.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>spfx</category>
      <category>react</category>
      <category>webpart</category>
    </item>
    <item>
      <title>Storing App Configuration in OneDrive with Microsoft Graph using an SPFx Web Part</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 18 Feb 2026 10:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/storing-app-configuration-in-onedrive-with-microsoft-graph-using-an-spfx-web-part-5djb</link>
      <guid>https://forem.com/guidozam/storing-app-configuration-in-onedrive-with-microsoft-graph-using-an-spfx-web-part-5djb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When building a SharePoint Framework web part, choosing where to store configuration can be surprisingly complex. SharePoint lists require provisioning, tenant properties can be restrictive, and hardcoded values aren’t maintainable nor a good practice. A cleaner alternative is to use Microsoft Graph—specifically the &lt;code&gt;/me/drive/special/approot&lt;/code&gt; endpoint—to store configuration files in a secure, app-scoped folder within the current user’s OneDrive.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/me/drive/special/approot&lt;/code&gt; path provides a dedicated storage location that’s automatically created and isolated to your Azure Entra ID app registration. This makes it ideal for storing JSON configuration for an SPFx web part without deploying additional infrastructure. In this post, we’ll look at how to configure permissions, access the endpoint from SPFx, and read/write configuration files using Microsoft Graph.&lt;/p&gt;

&lt;p&gt;In order to demonstrate how to use this special Microsoft Graph endpoint, I’ve created a sample web part that you can find &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/web%20parts/personal-settings" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The sample will allow the user to specify the content of the configuration file and also offer the ability to save or load the configuration from the Graph API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual appearance
&lt;/h2&gt;

&lt;p&gt;Starting with the visual appearance of the solution, here you can see the web part:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftest7iaovrpkm2n79x6i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftest7iaovrpkm2n79x6i.png" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The web part is composed of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Save Config&lt;/code&gt;: this button is used to save the input of the text field to the Graph API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Load Config&lt;/code&gt;: this button loads the configuration file from the Graph API.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Text area&lt;/code&gt;: used to insert the value to be saved to the configuration file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, it’s possible to specify the following JSON:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbi26wdep3h8woitqpeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbi26wdep3h8woitqpeb.png" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and saving it using the &lt;code&gt;Save Config&lt;/code&gt; button. The user will receive a message confirming the operation success:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpd89qnduhxmmyxeoafg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpd89qnduhxmmyxeoafg5.png" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sending the content of the file to the &lt;code&gt;/me/drive/special/approot&lt;/code&gt; Graph endpoint will save a file in the following OneDrive folder:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvz85dsio2kumxw02tt4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkvz85dsio2kumxw02tt4.png" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The created file will look like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc63clyllmf5nuspb6qh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjc63clyllmf5nuspb6qh.png" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The name of the file is defined in the web part code, it’s totally customizable and can be decided by the developer, in this sample it’s a JSON file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;p&gt;I won’t cover all the web part’s code, if you are interested in digging the whole code you can check the full sample solution code &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/web%20parts/personal-settings" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In detail, there’s a Graph service which is in charge of execute requests against the &lt;code&gt;/me/drive/special/approot&lt;/code&gt; Graph endpoint.&lt;/p&gt;

&lt;p&gt;First of all, to execute the requests, it’s needed to create a Graph client and to create it is enough to use the web part’s context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private async getGraphClient(): Promise&amp;lt;MSGraphClientV3&amp;gt; {
    if (!this.graphClient) {
        this.graphClient = 
          await this.context
                .msGraphClientFactory
                .getClient("3");
    }
    return this.graphClient;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that the &lt;code&gt;graphClient&lt;/code&gt; is available, it’s possible to interact with the Graph APIs.&lt;/p&gt;

&lt;p&gt;To save the specified JSON there’s a specific &lt;code&gt;uploadFile&lt;/code&gt; method. The interesting section of this method is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await graphClient
  .api(
      `/me/drive/special/approot:/${encodeURIComponent(fileName)}:/content`,
  )
  .version("v1.0")
  .header("Content-Type", contentType)
  .put(content);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a file with the specified &lt;code&gt;fileName&lt;/code&gt; and the &lt;code&gt;content&lt;/code&gt; as text.&lt;/p&gt;

&lt;p&gt;The other operation, needed in this sample, is the one to read the content of the file from the endpoint. The interesting section of the &lt;code&gt;readJsonFile&lt;/code&gt; method is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await graphClient
  .api(
      `/me/drive/special/approot:/${encodeURIComponent(itemName)}:/content`,
  )
  .version("v1.0")
  .responseType(ResponseType.TEXT)
  .get();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This partial code retrieves the content of the file with the specific &lt;code&gt;fileName&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Those are the most interesting code sections of this sample, if you’re interested in knowing more check out the full sample on GitHub.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;/me/drive/special/approot&lt;/code&gt; Graph endpoint is very useful when it comes to saving configuration for the current user, this is because it doesn’t need anything else such as a SharePoint list to store the user specific configuration.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>microsoftgraph</category>
      <category>spfx</category>
      <category>onedrive</category>
    </item>
    <item>
      <title>Using the PropertyFieldOrder from the PnP reusable property controls</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 04 Feb 2026 10:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/using-the-propertyfieldorder-from-the-pnp-reusable-property-controls-4a4c</link>
      <guid>https://forem.com/guidozam/using-the-propertyfieldorder-from-the-pnp-reusable-property-controls-4a4c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Proceeding our dive into the PnP reusable property pane controls, I want to cover the &lt;code&gt;PropertyFieldOrder&lt;/code&gt; control.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The PnP reusable property pane controls is a package that contains a lot of useful controls that can be used in any SharePoint Framework web part’s property pane, if you want to know more about this you can check out the official site &lt;a href="https://pnp.github.io/sp-dev-fx-property-controls" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To demonstrate the various capabilities of the control, I’ve created a sample solution which you can find &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/pnp-property-controls/pnp-property-pane-order" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The sample solution contains a simple web part that shows how the &lt;code&gt;PropertyFieldOrder&lt;/code&gt; works.&lt;/p&gt;

&lt;p&gt;In few words, the control allows the user to choose the order of a predefined list of entries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual appearance
&lt;/h2&gt;

&lt;p&gt;Starting from how the component appears, I’ve created a sample web part which simply displays the entries used in the &lt;code&gt;PropertyFieldOrder&lt;/code&gt; control. To make this sample a little more appealing I’ve imagined a racing with six participants:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljy2j0f4sbdj4rpky77w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljy2j0f4sbdj4rpky77w.png" width="800" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PropertyFieldOrder&lt;/code&gt; control is used in the property pane, so let’s see how this is rendered:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphkqbg7cqioucpo6p5dh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fphkqbg7cqioucpo6p5dh.png" width="666" height="786"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As usual, in the sample solution, you can find multiple instances of the control, each instance demonstrate a specific property of the control.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PropertyFieldOrder&lt;/code&gt; control allows to reorder a list of items so here, for example, if Princess Peach throws a tortoise to Bowser, the rank can change to the following (Bowser lose two positions):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hqvw21x7uoqprl1l6xu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hqvw21x7uoqprl1l6xu.png" width="636" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is possible either by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clicking on the up and down arrows.&lt;/li&gt;
&lt;li&gt;Dragging and dropping the item to the desired position.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Proceeding with other control instances, it’s possible to disable the control. As a result all the arrows and the drag and drop capabilities are disabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnlbqncv3dblieetrn6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnlbqncv3dblieetrn6p.png" width="664" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The control offers the ability to modify the user experience, for example you can hide the up and down arrows, leaving only the ability to drag and drop the items:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwmrkobmvn558yio6fec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwmrkobmvn558yio6fec.png" width="652" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In opposition with the previous instance, it’s also possible to disable the drag and drop capability, leaving only the ability to use the arrows to move the items around:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlvyiub0to11mjqmfday.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlvyiub0to11mjqmfday.png" width="662" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next instance, is used to highlight the ability to specify a custom Fluent UI icon to be shown instead of the arrows. By default the &lt;code&gt;ChevronUpSmall&lt;/code&gt; and &lt;code&gt;ChevronDownSmall&lt;/code&gt; icons are used:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyaugqvu9kc4wbnfj1eyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyaugqvu9kc4wbnfj1eyy.png" width="670" height="876"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you change the icon names, for example to &lt;code&gt;TriangleSolidUp12&lt;/code&gt; and &lt;code&gt;TriangleSolidDown12&lt;/code&gt; you can have a rendering like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0v4l8svqp6v1lg6cp2iu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0v4l8svqp6v1lg6cp2iu.png" width="662" height="874"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, the last instance present in the sample solution, is the one demonstrating how to perform a custom rendering of each item:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw47qgrbeklng8pk78ogf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw47qgrbeklng8pk78ogf.png" width="660" height="672"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, after having an idea of the possibilities, let’s cover more in detail the code used.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;To use the PnP property controls first you need to install the package&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @pnp/spfx-property-controls --save --save-exact
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;After the installation of the package you can proceed with the following explanations for the &lt;code&gt;PropertyFieldOrder&lt;/code&gt;&lt;/em&gt; &lt;em&gt;control.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;To use the control you have to import it in the web part file with the following statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { 
  PropertyFieldOrder
} from '@pnp/spfx-property-controls/lib/PropertyFieldOrder';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, that we have the SharePoint Framework solution ready, let’s cover each single control instance in more detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minimal instance
&lt;/h3&gt;

&lt;p&gt;The minimal instance of the control shows what is the minimum configuration needed to use the &lt;code&gt;PropertyFieldOrder&lt;/code&gt;. Each of the following instances will have the same set of basic properties plus the instance specific ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PropertyFieldOrder('minimalOrder', {
  key: 'minimalOrderFieldId',
  label: strings.MinimalOrderLabel,
  items: this.properties.minimalOrder,
  textProperty: 'text',
  properties: this.properties,
  onPropertyChange: this.onPropertyPaneFieldChanged
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this minimal configuration, I think the two most interesting properties are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;items&lt;/code&gt;: which contains the array of items to be shown in the control.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;textProperty&lt;/code&gt;: which contains the name of the object’s property that contains the text to be displayed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The other properties are pretty self explanatory, but for the sake of completeness here is a brief explanation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;key&lt;/code&gt;: is the identifier of the control instance.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;label&lt;/code&gt;: is the text shown for the control.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;properties&lt;/code&gt;: is a binding to the web part properties.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onPropertyChange&lt;/code&gt;: is a binding to the &lt;code&gt;onPropertyPaneFieldChanged&lt;/code&gt; method.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disabled instance
&lt;/h3&gt;

&lt;p&gt;In case you need to disable the control that’s easily done using the &lt;code&gt;disabled&lt;/code&gt; property specifying a boolean value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PropertyFieldOrder('disabledOrder', {
  key: 'disabledOrderFieldId',
  label: strings.DisabledOrderLabel,
  items: this.properties.disabledOrder,
  textProperty: 'text',
  disabled: true,
  properties: this.properties,
  onPropertyChange: this.onPropertyPaneFieldChanged
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting the &lt;code&gt;disabled&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt; will disable the control, setting it to &lt;code&gt;false&lt;/code&gt; will enable the control.&lt;/p&gt;

&lt;h3&gt;
  
  
  No arrows instance
&lt;/h3&gt;

&lt;p&gt;Removing the arrows from the user interface might be useful and that’s possible by setting the &lt;code&gt;removeArrows&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PropertyFieldOrder('noArrowsOrder', {
  key: 'noArrowsOrderFieldId',
  label: strings.NoArrowsOrderLabel,
  items: this.properties.noArrowsOrder,
  textProperty: 'text',
  removeArrows: true,
  properties: this.properties,
  onPropertyChange: this.onPropertyPaneFieldChanged
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  No drag and drop instance
&lt;/h3&gt;

&lt;p&gt;In case you find the arrows a nice UI addition but you don’t want to allow users to drag and drop the items around, you can disable this by setting the &lt;code&gt;disableDragAndDrop&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PropertyFieldOrder('noDragDropOrder', {
  key: 'noDragDropOrderFieldId',
  label: strings.NoDragDropOrderLabel,
  items: this.properties.noDragDropOrder,
  textProperty: 'text',
  disableDragAndDrop: true,
  properties: this.properties,
  onPropertyChange: this.onPropertyPaneFieldChanged
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom icons instance
&lt;/h3&gt;

&lt;p&gt;This instance demonstrates how to change the default icon for the arrows. The custom icons can be chosen from the Fluent UI ones. In the sample, there are a couple of text boxes to allow users to specify which icon to use for either the two icons.&lt;/p&gt;

&lt;p&gt;The properties to specify the custom icons are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;moveUpIconName&lt;/code&gt;: the Fluent UI icon name to be used as the up arrow. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;moveDownIconName&lt;/code&gt;: the Fluent UI icon name to be used for the down arrow.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PropertyFieldOrder('customIconsOrder', {
  key: 'customIconsOrderFieldId',
  label: strings.CustomIconsOrderLabel,
  items: this.properties.customIconsOrder,
  textProperty: 'text',
  moveUpIconName: this.properties.customUpIcon,
  moveDownIconName: this.properties.customDownIcon,
  properties: this.properties,
  onPropertyChange: this.onPropertyPaneFieldChanged
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom render instance
&lt;/h3&gt;

&lt;p&gt;The last instance present in the sample solution is the one allowing to customize the rendering of the items.&lt;/p&gt;

&lt;p&gt;In the sample, there is the following array of items:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const defaultMarioCharacters = [
  {"text": "Mario", "icon": "🍄"},
  {"text": "Luigi", "icon": "👑"},
  {"text": "Princess Peach", "icon": "👸"},
  {"text": "Bowser", "icon": "🐲"},
  {"text": "Yoshi", "icon": "🦕"},
  {"text": "Toad", "icon": "🍄"}
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each item, there are a &lt;code&gt;text&lt;/code&gt; and an &lt;code&gt;icon&lt;/code&gt; properties. Say that we want to display the icon near the text inside of the &lt;code&gt;PropertyFieldOrder&lt;/code&gt; control, that is possible by setting the property &lt;code&gt;onRenderItem&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PropertyFieldOrder('customRenderOrder', {
  key: 'customeRenderOrderFieldId',
  label: strings.CustomRenderLabel,
  items: this.properties.customRenderOrder,
  onRenderItem: this.renderMarioCharacter,
  properties: this.properties,
  onPropertyChange: this.onPropertyPaneFieldChanged,
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the sample, the method used for rendering the items is the following one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private renderMarioCharacter = (
  item: {
    text: string, icon: string
  },
  index: number): JSX.Element =&amp;gt; {

  return React.createElement('span', {
    style: { display: 'flex', alignItems: 'center' }
  },
    React.createElement('span', {
      style: { marginRight: '8px', fontSize: '16px' }
    }, item.icon),
    item.text
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method will simply create a &lt;code&gt;span&lt;/code&gt; element and putting the icon inside another &lt;code&gt;span&lt;/code&gt; element, alongside the text of the item.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;PropertyFieldOrder&lt;/code&gt; control is an awesome ready to use and customisable control. With this you can quickly allow users to order items without having to develop all the necessary code yourself.&lt;/p&gt;

&lt;p&gt;If you’re interested in knowing more, you can check out the official documentation &lt;a href="https://pnp.github.io/sp-dev-fx-property-controls/controls/PropertyFieldOrder/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>spfx</category>
      <category>pnp</category>
      <category>propertypane</category>
    </item>
    <item>
      <title>Render a Mermaid diagram in an SPFx web part</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 14 Jan 2026 10:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/render-a-mermaid-diagram-in-an-spfx-web-part-3g13</link>
      <guid>https://forem.com/guidozam/render-a-mermaid-diagram-in-an-spfx-web-part-3g13</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Mermaid is quite useful, no doubt about that. It might also be useful to display diagrams in a SharePoint Online site. So, why not displaying a mermaid diagram in an SPFx web part?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don’t know Mermaid you can have a look &lt;a href="https://mermaid.js.org" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Visual appearance
&lt;/h2&gt;

&lt;p&gt;Let’s start having a look at a sample solution I’ve prepared. The solution is composed of a web part that allows, through the property pane, to configure the diagram to be shown.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find the code &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/web%20parts/mermaid-diagram" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First of all, in the following screenshot, you can see how the web part displays:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbrb06p0qds09dg97gsw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpbrb06p0qds09dg97gsw.png" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This web part, as said, is configured through the property pane:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5d9folnxcun5idl41fpq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5d9folnxcun5idl41fpq.png" width="680" height="932"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The property pane allows to configure different properties divided in two different sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Configuration&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Title&lt;/code&gt;: the title to be displayed for the web part.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Mermaid&lt;/code&gt; Diagram: the actual Mermaid diagram to be displayed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;Styling&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Show Title&lt;/code&gt;: allow to hide or display the title of the web part.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Show Border&lt;/code&gt;: allow to hide or show the border of the web part.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;To have a better user experience, I’ve used the &lt;code&gt;PropertyFieldCodeEditor&lt;/code&gt; (&lt;a href="https://pnp.github.io/sp-dev-fx-property-controls/controls/PropertyFieldCodeEditor/" rel="noopener noreferrer"&gt;more here&lt;/a&gt;) from the PnP reusable property pane controls (&lt;a href="https://pnp.github.io/sp-dev-fx-property-controls/" rel="noopener noreferrer"&gt;more here&lt;/a&gt;) in order to allow code editing inside the property pane.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, it’s possible to specify a Mermaid code in the property pane with a very nice code editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5amg2vonmh3345u9flfg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5amg2vonmh3345u9flfg.png" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once set the Mermaid diagram, you can have it displayed directly in the web part:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gcuwxeezxkdsnq27t8r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gcuwxeezxkdsnq27t8r.png" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want some more idea of the capabilities, have a look at the readme file of the project &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/web%20parts/mermaid-diagram" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Show me the code
&lt;/h2&gt;

&lt;p&gt;Now that you have a clear understanding of the appearance of the web part, let’s cover how to implement it.&lt;/p&gt;

&lt;p&gt;To render a Mermaid diagram, first you need to install the &lt;code&gt;mermaid&lt;/code&gt; package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i mermaid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;I won’t cover all the code here, if you’re interested in having a look at the whole project you can find it &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/web%20parts/mermaid-diagram" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After installing the package, you need to import it into your component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import mermaid from 'mermaid';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After importing the package, you will need to initialize Mermaid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mermaid.initialize({
  startOnLoad: false,
  theme: 'default',
  securityLevel: 'strict',
  htmlLabels: false
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After initialization, you can use the package to render the actual SVG and insert it into the target HTML element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { svg } = await mermaid.render(
  diagramId,
  this.props.mermaidDiagram
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The arguments for the Mermaid &lt;code&gt;render&lt;/code&gt; method are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;diagramId&lt;/code&gt;: which is simply a unique ID for the diagram.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;this.props.mermaidDiagram&lt;/code&gt;: is the actual text of the Mermaid diagram to be rendered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the generation of the Mermaid diagram it’s a simple matter of showing it in the web part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.diagramRef.current.innerHTML = svg;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;I think that Mermaid is pretty useful and powerful, particularly when it comes to visualizing complex data and workflows. It can be a very interesting addition to your SharePoint Online site, as it allows users to create diagrams and flowcharts with ease, enhancing the overall user experience.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>spfx</category>
      <category>mermaid</category>
      <category>pnp</category>
      <category>diagrams</category>
    </item>
    <item>
      <title>Automate Microsoft MFA login using Playwright</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 17 Dec 2025 10:00:00 +0000</pubDate>
      <link>https://forem.com/guidozam/automate-microsoft-mfa-login-using-playwright-1lhc</link>
      <guid>https://forem.com/guidozam/automate-microsoft-mfa-login-using-playwright-1lhc</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;During a session at ESPC 25, where I and the awesome Peter Paul Kirschner &lt;a href="https://www.sharepointeurope.com/events/developing-testing-and-deploying-sharepoint-framework-solutions-with-success/" rel="noopener noreferrer"&gt;talked about developing, testing and deploying a SPFx solution&lt;/a&gt;, a person asked if Playwright supports MFA: the answer is yes, using a TOTP.&lt;/p&gt;

&lt;p&gt;This article wants to be an answer to that person and to everyone who wants to use Playwright but has strict company policies regarding MFA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;I think that’s obvious but, in order to use MFA (Multi-Factor Authentication) in Playwright, we need MFA to be set up correctly.&lt;/p&gt;

&lt;p&gt;More specifically, we need an MFA-enabled account configured to utilize an authenticator app with a &lt;strong&gt;time-based one-time password (TOTP)&lt;/strong&gt; system in place.&lt;/p&gt;

&lt;p&gt;The TOTP itself is a temporary code generated through an algorithm that changes every 30 seconds. This dynamic nature of TOTP codes adds an extra layer of protection, making it significantly harder for unauthorized users to gain access. The codes are only valid for a brief period, ensuring that even if someone were to intercept a code, it would quickly become useless.&lt;/p&gt;

&lt;p&gt;The TOTP algorithm works by generating a temporary code using a secret key (which is shared between the server and the authenticator app) and the current time, ensuring that each generated code is unique and time-sensitive.&lt;/p&gt;

&lt;p&gt;To implement this in a testing environment with Playwright, we can leverage a powerful library for Node.js called &lt;a href="https://www.npmjs.com/package/otpauth" rel="noopener noreferrer"&gt;OTPAuth&lt;/a&gt;. This library simplifies the process of generating TOTP codes, and it can be seamlessly integrated into our automation scripts. By utilizing OTPAuth, we can efficiently create the required TOTP codes needed for the login process in our automated test cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add TOTP to an account
&lt;/h3&gt;

&lt;p&gt;To add a TOTP to an account, you need to go to the specific account’s security settings.&lt;/p&gt;

&lt;p&gt;First, go to the &lt;a href="https://mysignins.microsoft.com/security-info" rel="noopener noreferrer"&gt;Security info&lt;/a&gt; page of the account you want to use.&lt;/p&gt;

&lt;p&gt;Click the  &lt;strong&gt;Add sign-in method&lt;/strong&gt;  button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4qa48g116zu20sd3z67.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk4qa48g116zu20sd3z67.png" width="444" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select  &lt;strong&gt;Microsoft Authenticator&lt;/strong&gt;  and click on  &lt;strong&gt;Add&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqemrdw7bf3f4iwu9n6q6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqemrdw7bf3f4iwu9n6q6.png" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the  &lt;strong&gt;Set up a different authenticator app&lt;/strong&gt;  link:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmbut3dqbkn7sxcg2ars.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftmbut3dqbkn7sxcg2ars.png" width="800" height="930"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the following dialog, click on the  &lt;strong&gt;Next&lt;/strong&gt;  button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr79uwx7lk0qcw0cw3v0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr79uwx7lk0qcw0cw3v0d.png" width="800" height="739"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the  &lt;strong&gt;Can’t scan the QR code?&lt;/strong&gt;  link&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjlfe2y8pfzok33q6a5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjlfe2y8pfzok33q6a5b.png" width="800" height="875"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the  &lt;strong&gt;Secret key&lt;/strong&gt;  and keep it safe (don’t share it) as you will need it later:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxiebgm6sb99lyaa0qwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxiebgm6sb99lyaa0qwx.png" width="800" height="788"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate TOTP
&lt;/h2&gt;

&lt;p&gt;To automatically generate a TOTP we will use the &lt;code&gt;otpauth&lt;/code&gt; package available using NPM.&lt;/p&gt;

&lt;p&gt;To generate a TOTP you will need to import the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as OTPAuth from "otpauth";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, you will need to instantiate the TOTP class with the needed configuration. In the sample I’ve used the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let totp = new OTPAuth.TOTP({
  issuer: "Microsoft",
  label: process.env.MFA_USERNAME,
  algorithm: "SHA1",
  digits: 6,
  period: 30,
  secret: process.env.MFA_TOTP_SECRET,
});
const code = totp.generate();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code is used to generate a new TOTP using a specific secret. This secret is the one copied before.&lt;/p&gt;

&lt;p&gt;To avoid having the secret hard coded you can set it into the .env file and reuse where needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Playwright configuration
&lt;/h2&gt;

&lt;p&gt;Now, that we have set up the TOTP and have understood how to generate a new TOTP automatically, it’s possible to configure the login in Playwright.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;playwright.config.ts&lt;/code&gt; file, in the &lt;code&gt;projects&lt;/code&gt; section, you can configure a step for handling authentication which can be performed for each other steps.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default defineConfig({
  // omitted for brevity ...
  projects: [
    {
      name: "setup",
      testMatch: /mfa.setup.ts/
    },
    {
      name: "Chromium",
      // omitted for brevity ...
      dependencies: ["setup"], // Will run first
    }
  // omitted for brevity ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;mfa.setup.ts&lt;/code&gt; file, aside of the rest of the code for handling the login, you can then use the code we’ve seen in the previous section to fill in the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const otpInput = await page.waitForSelector("input#idTxtBx_SAOTCC_OTC");

let totp = new OTPAuth.TOTP({
  issuer: "Microsoft",
  label: process.env.MFA_USERNAME,
  algorithm: "SHA1",
  digits: 6,
  period: 30,
  secret: process.env.MFA_TOTP_SECRET,
});

const code = totp.generate();
await otpInput.fill(code);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you’re ready to execute your tests!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;MFA can be challenging, but luckily is quite simple to setup and use it with Playwright! In this way you can be compliant with your company policies and still have a nice and running testing setup!&lt;/p&gt;

&lt;p&gt;If you need to have a look at how I’ve set up the project you can find it on GitHub &lt;a href="https://github.com/GuidoZam/espc-spfx-session-demo/tree/mfa-support" rel="noopener noreferrer"&gt;here on the mfa-support branch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>e2e</category>
      <category>mfa</category>
      <category>playwright</category>
    </item>
  </channel>
</rss>
