<?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>DEV Community: Guido Zambarda</title>
    <description>The latest articles on DEV Community by Guido Zambarda (@guidozam).</description>
    <link>https://dev.to/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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1228379%2F9a604eff-a326-40fa-87d6-07caa19af80c.jpeg</url>
      <title>DEV Community: Guido Zambarda</title>
      <link>https://dev.to/guidozam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/guidozam"/>
    <language>en</language>
    <item>
      <title>Pro-code Declarative Agent with SharePoint knowledge base</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 24 Jun 2026 11:30:00 +0000</pubDate>
      <link>https://dev.to/guidozam/pro-code-declarative-agent-with-sharepoint-knowledge-base-ekd</link>
      <guid>https://dev.to/guidozam/pro-code-declarative-agent-with-sharepoint-knowledge-base-ekd</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[Disclaimer]&lt;/strong&gt; In this post I will not cover how to create a declarative agent, if you’re interested in knowing the basics you can check my previous post &lt;a href="https://iamguidozam.blog/2026/05/06/create-your-first-declarative-agent-the-pro-code-way-with-vscode/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When creating declarative agents the &lt;strong&gt;pro-code&lt;/strong&gt; way, there are plenty of possibilities to customise your agents. In this post, I will cover how to add a SharePoint Online site as knowledge base for a declarative agent.&lt;/p&gt;

&lt;p&gt;The sample declarative agent I’ve created is based on a SharePoint Online site that contains Microsoft Copilot Studio licensing PDFs, let’s see how it displays and how it works.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you’re interested in checking the sample code you can find it &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/agents/da-spo-knowledge" 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;Nowadays I think everyone already know what is the interface for a declarative agent, however, just to give a little bit of context, I want to show you a couple of screenshots.&lt;/p&gt;

&lt;p&gt;As every declarative agent we have a chat-like interface:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftnpnkmc2ocm1sz8bidv0.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftnpnkmc2ocm1sz8bidv0.png" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To speed up the testing phase I’ve added a suggested prompt that query the agent about the licensing options of Microsoft Copilot Studio.&lt;/p&gt;

&lt;p&gt;As a result the agent will list all the available licensing types of MCS in the PDFs uploaded to my SharePoint Online site.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy9yhtm0sfmbp2e2hz2dh.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy9yhtm0sfmbp2e2hz2dh.png" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this particular sample, there isn’t much work to do in order to support the SharePoint Online site as knowledge base, you simply have to define the capability to reach SPO and specify an identifier of the resource.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;declarativeAgent.json&lt;/code&gt; file, alongside the &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt; and &lt;code&gt;instructions&lt;/code&gt; properties, it’s also possible to define the &lt;code&gt;capabilities&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;capabilities&lt;/code&gt; property contains the capabilities that the agent will have. To define a SharePoint Online site as knowledge base, you simply have to define an object with name &lt;code&gt;OneDriveAndSharePoint&lt;/code&gt;, like the following:&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="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OneDriveAndSharePoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"items_by_url"&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="nl"&gt;"url"&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://&amp;lt;your tenant&amp;gt;.sharepoint.com/sites/&amp;lt;your site&amp;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="err"&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 object specify that the agent has the capability to access OneDrive and SharePoint Online. This object support two ways to define the items, one is the one you can see in the code snippet above using &lt;code&gt;items_by_url&lt;/code&gt;, the other way is to use &lt;code&gt;items_by_sharepoint_ids&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;items_by_url&lt;/code&gt; will simply require to have the full URL to the item you want to use as knowledge base. &lt;strong&gt;If you don’t specify any, the whole tenant will be accessible, if you specify a SharePoint Online site the whole content of the site will be accessible to the declarative agent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;items_by_sharepoint_ids&lt;/code&gt; is slightly different, you will require to specify a more complex object that also contains the &lt;strong&gt;IDs to identify the target site, library or item&lt;/strong&gt;. To have an idea, here are some of the properties with placeholder values:&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="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"items_by_sharepoint_ids"&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="nl"&gt;"site_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;site-id&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"list_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;list-id&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"unique_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;unique-id&amp;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;This is just to give you an idea of the possibilities, there are also other properties that I will not cover here but that you can check the JSON schema on the official documentation &lt;a href="https://learn.microsoft.com/en-us/microsoft-365/copilot/extensibility/declarative-agent-manifest-1.7?tabs=json#json-schema" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Adding a knowledge base to a declarative agent created with a pro-code approach is a very easy and straightforward process. Using SharePoint Online as knowledge source will give plenty of possibilities to create specialised site(s) to be used by declarative agents as knowledge source(s).&lt;/p&gt;

&lt;p&gt;If you’ve never created a declarative agent I suggest that you start with my &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/agents/da-spo-knowledge" rel="noopener noreferrer"&gt;previous post&lt;/a&gt; or navigate to the &lt;a href="https://aka.ms/copilot-devcamp" rel="noopener noreferrer"&gt;Copilot dev camp&lt;/a&gt;, which is a very comprehensive site with multiple ways of creating your declarative/custom engine/low-code/no-code agents&lt;/p&gt;

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

</description>
      <category>m365copilot</category>
      <category>declarativeagent</category>
      <category>sharepoint</category>
    </item>
    <item>
      <title>Use the FilePicker from the PnP reusable React controls</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 10 Jun 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/guidozam/use-the-filepicker-from-the-pnp-reusable-react-controls-1j23</link>
      <guid>https://dev.to/guidozam/use-the-filepicker-from-the-pnp-reusable-react-controls-1j23</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;code&gt;FilePicker&lt;/code&gt; control.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FilePicker&lt;/code&gt; control is a powerful and versatile component that allows users to browse and select files from various sources within your SharePoint Framework solutions. Whether you need to let users pick files from SharePoint document libraries, OneDrive, recent files, or even upload new files, the &lt;code&gt;FilePicker&lt;/code&gt; control has you covered.&lt;/p&gt;

&lt;blockquote&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-filepicker" 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 with the visual appearance of the sample solution.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FilePicker&lt;/code&gt; control provides a clean and intuitive interface for file selection, starting from a simple button like the following one:&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%2Fz7big26ekv02j7hzsu2x.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%2Fz7big26ekv02j7hzsu2x.png" width="306" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That, once clicked, opens a panel where it’s possible to select the file(s) to be selected.&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%2Fqj2ji5tx9eaieep8pbke.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%2Fqj2ji5tx9eaieep8pbke.png" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you click the button to open the file picker, a panel opens displaying multiple tabs that represent different possible file sources:&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Recent&lt;/strong&gt; : Displays recently modified files based on search results.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Stock Images&lt;/strong&gt; : Access to stock image libraries.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;OneDrive&lt;/strong&gt; : Select files from the user’s OneDrive.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Site&lt;/strong&gt; : Select content from the current site.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Upload&lt;/strong&gt; : Upload a single file from your local drive.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Upload Files&lt;/strong&gt; : Upload multiple files at once.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;From a Link&lt;/strong&gt; : Paste a link to a file.&lt;/p&gt;

&lt;p&gt;The control also includes breadcrumb navigation for easy folder traversal and implements paged data loading to ensure optimal performance even with large document libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minimal sample
&lt;/h3&gt;

&lt;p&gt;The minimal configuration sample just demonstrates the very basic configuration of the control.&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%2F4ue6hkzqvdbzjfscpu43.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%2F4ue6hkzqvdbzjfscpu43.png" width="799" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aside of the grey area underneath the control, which is just used to list the selected file(s), the control renders a label and a button which are customisable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom button icon
&lt;/h3&gt;

&lt;p&gt;This sample highlights the ability to change the button into a custom icon.&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%2Fujtxyn759fjxhf97dk4d.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%2Fujtxyn759fjxhf97dk4d.png" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  onChange handler
&lt;/h3&gt;

&lt;p&gt;The onChange sample demonstrate how to use the corresponding property in order to catch when the selection change.&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%2Fmgbxt28ydhxqm83hyygx.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%2Fmgbxt28ydhxqm83hyygx.png" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this sample, the &lt;code&gt;onChange&lt;/code&gt; event just triggers a message bar and also a new row in the console logging to track the change event:&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%2Feo4ua55jqvnxw5r1m0te.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%2Feo4ua55jqvnxw5r1m0te.png" width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  onCancel handler
&lt;/h3&gt;

&lt;p&gt;The onCancel sample shows how to use the event in order to track when the panel is cancelled.&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%2F55d2udfxp2rfwy0edf1w.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%2F55d2udfxp2rfwy0edf1w.png" width="798" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the previous sample, this one shows a message bar when the panel is cancelled alongside a new row in the browser’s console.&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%2Fz46th9a5f8jz81vob9sa.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%2Fz46th9a5f8jz81vob9sa.png" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  File type restrictions
&lt;/h3&gt;

&lt;p&gt;This sample demonstrates how to restrict the selectable files.&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%2Fwrymgtsr7xmfbsee6ax7.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%2Fwrymgtsr7xmfbsee6ax7.png" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This simply doesn’t show anything special, but when the panel opens it will allow the selection of only DOCX or PDF files, this is totally customisable and I will cover that in the code section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Required field
&lt;/h3&gt;

&lt;p&gt;As many of the components offered by the PnP reusable React controls, it’s also possible to specify that the control is a required one:&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%2Fevxtpe4seu2nsegg7xp0.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%2Fevxtpe4seu2nsegg7xp0.png" width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Disabled state
&lt;/h3&gt;

&lt;p&gt;When needed, it’s possible to disable the control:&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%2Faguq1xzwkyhvme877xib.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%2Faguq1xzwkyhvme877xib.png" width="799" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hidden control
&lt;/h3&gt;

&lt;p&gt;It’s also possible to not display the default button and trigger the panel from a hidden control. In this sample I’ve used another button to toggle the visibility of the panel:&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%2Fljxk3gg61o7cyoskz7fp.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%2Fljxk3gg61o7cyoskz7fp.png" width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tab visibility control
&lt;/h3&gt;

&lt;p&gt;This particular instance shows how it’s possible to select which tab to show or hide from the panel, for example if you choose 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%2F8mj1dfqq0pbaz9k4x3jo.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%2F8mj1dfqq0pbaz9k4x3jo.png" width="800" height="757"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The resulting panel will be 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%2F5p5id9zs5t0czvnqzm3c.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%2F5p5id9zs5t0czvnqzm3c.png" width="800" height="340"&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 FilePicker control.&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;FilePicker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;IFilePickerResult&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/FilePicker&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 this sample solution, I’ve created multiple instances of the control to demonstrate different configurations and use cases of the &lt;code&gt;FilePicker&lt;/code&gt; control. Let’s explore each one!&lt;/p&gt;

&lt;h4&gt;
  
  
  Minimal Configuration
&lt;/h4&gt;

&lt;p&gt;The most basic implementation requires only two properties:&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;FilePicker&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Select a file"&lt;/span&gt;
  &lt;span class="na"&gt;onSave&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;selectedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;context&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&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;p&gt;Key properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;onSave&lt;/code&gt;: Handler called when a file is selected and saved.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;context&lt;/code&gt;: The web part context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;label&lt;/code&gt; property is not really required, but without specifying it there won’t be any text displayed.&lt;/p&gt;

&lt;p&gt;This minimal configuration gives you a fully functional file picker with all tabs enabled by default.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom Button Icon
&lt;/h4&gt;

&lt;p&gt;Instead of a standard button, you can display an icon button using the &lt;code&gt;buttonIcon&lt;/code&gt; property. You can further customize the icon appearance with &lt;code&gt;buttonIconProps&lt;/code&gt;:&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;FilePicker&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Pick Document"&lt;/span&gt;
  &lt;span class="na"&gt;buttonIcon&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"FabricFolder"&lt;/span&gt;
  &lt;span class="na"&gt;buttonIconProps&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;iconName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FabricFolder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#0078d4&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onSave&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;selectedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;context&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&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;p&gt;Key properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;buttonIcon&lt;/code&gt;: Specifies which Fluent UI icon to display.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;buttonIconProps&lt;/code&gt;: Additional properties for customizing the icon (size, color, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  onChange handler
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;onChange&lt;/code&gt; handler is triggered whenever the file selection changes in the picker panel, even before the user clicks save. This is useful for real-time validation or preview.&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;FilePicker&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Select a file"&lt;/span&gt;
  &lt;span class="na"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Browse Files"&lt;/span&gt;
  &lt;span class="na"&gt;onSave&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;selectedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onChange&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&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;File selection changed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;files&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;selectionChanged&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;context&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&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;h4&gt;
  
  
  onCancel handler
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;onCancel&lt;/code&gt; handler is called when the user closes the FilePicker panel.&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;FilePicker&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Select a file"&lt;/span&gt;
  &lt;span class="na"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Browse Files"&lt;/span&gt;
  &lt;span class="na"&gt;onSave&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;selectedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onCancel&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="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;File picker cancelled&lt;/span&gt;&lt;span class="dl"&gt;'&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;cancelled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;context&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&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;h4&gt;
  
  
  File Type Restrictions
&lt;/h4&gt;

&lt;p&gt;Use the &lt;code&gt;accepts&lt;/code&gt; property to restrict file selection to specific file types. This example only allows DOCX and PDF files.&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;FilePicker&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Select document (DOCX or PDF only)"&lt;/span&gt;
  &lt;span class="na"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Browse Files"&lt;/span&gt;
  &lt;span class="na"&gt;accepts&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.docx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onSave&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;selectedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;context&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&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;p&gt;The &lt;code&gt;accepts&lt;/code&gt; property support an array of string representing the extensions to be supported.&lt;/p&gt;

&lt;h4&gt;
  
  
  Required
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;required&lt;/code&gt; property adds a visual indication that file selection is mandatory.&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;FilePicker&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Select a required file"&lt;/span&gt;
  &lt;span class="na"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Browse Files"&lt;/span&gt;
  &lt;span class="na"&gt;required&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;onSave&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;selectedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;context&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&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;p&gt;The &lt;code&gt;required&lt;/code&gt; property is a boolean flag that adds an asterisk (*) to the label. This is particularly useful in forms where file upload is mandatory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Disabled
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;disabled&lt;/code&gt; property prevents user interaction with the &lt;code&gt;FilePicker&lt;/code&gt;.&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;FilePicker&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Disabled file picker"&lt;/span&gt;
  &lt;span class="na"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Browse Files"&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;onSave&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;selectedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;context&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&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;p&gt;This is useful if you need to conditionally disable the picker based on form state, user permissions, or other business logic.&lt;/p&gt;

&lt;h4&gt;
  
  
  Hidden Control with Programmatic Panel Control
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;hidden&lt;/code&gt; property hides the picker button while still allowing you to control the panel visibility programmatically using &lt;code&gt;isPanelOpen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the sample solution, there is a button to handle the state change:&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;DefaultButton&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Toggle Picker Visibility"&lt;/span&gt;
  &lt;span class="na"&gt;onClick&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="o"&gt;=&amp;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;panelOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;panelOpen&lt;/span&gt; &lt;span class="p"&gt;})&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;And then, there is the control that displays the panel only when the previous button is clicked:&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;FilePicker&lt;/span&gt;
  &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Hidden file picker (controlled programmatically)"&lt;/span&gt;
  &lt;span class="na"&gt;buttonLabel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Browse Files"&lt;/span&gt;
  &lt;span class="na"&gt;hidden&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;isPanelOpen&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;panelOpen&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onSave&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="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&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;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;selectedFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;panelOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;onCancel&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="o"&gt;=&amp;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;panelOpen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;context&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;context&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;h4&gt;
  
  
  Tab visibility
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;FilePicker&lt;/code&gt; control allows many customisation, there are a bunch of properties to personalize the available tabs in the panel that allows selection of files.&lt;/p&gt;

&lt;p&gt;Following a list of the available tab visibility properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;hideRecentTab&lt;/code&gt;: handle visibility of the RecentTab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hideWebSearchTab&lt;/code&gt;: handle visibility of the WebSearchTab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hideStockImages&lt;/code&gt;: handle visibility of the StockimagesTab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hideOrganisationalAssetTab&lt;/code&gt;: handle visibility of the OrganisationalAssetTab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hideOneDriveTab&lt;/code&gt;: handle visibility of the OneDriveTab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hideSiteFilesTab&lt;/code&gt;: handle visibility of the SiteFilesTab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hideLocalUploadTab&lt;/code&gt;: handle visibility of the LocalUploadTab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hideLocalMultipleUploadTab&lt;/code&gt;: handle visibility of the LocalMultipleUploadTab.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hideLinkUploadTab&lt;/code&gt;: handle visibility of the LinkUploadTab.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Conclusions
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;FilePicker&lt;/code&gt; control is an incredibly powerful and flexible solution for file selection scenarios in SharePoint Framework applications.&lt;/p&gt;

&lt;p&gt;Whether you need a simple file picker or a complex file selection workflow with custom validation and UI, the &lt;code&gt;FilePicker&lt;/code&gt; control provides all the tools you need. The comprehensive feature set, combined with minimal required code, makes it an essential component for any SharePoint Framework developer working with files.&lt;/p&gt;

&lt;p&gt;By leveraging the different configuration options shown in these examples, you can create exactly the file selection experience your users need, while maintaining clean, maintainable code through proper localization and separation of concerns.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this blog post I didn’t cover all the available properties, if you’re interested in knowing more you can find the official documentation &lt;a href="https://pnp.github.io/sp-dev-fx-controls-react/controls/FilePicker/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

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

</description>
      <category>spfx</category>
      <category>pnp</category>
      <category>react</category>
    </item>
    <item>
      <title>New Feature for SPFx extensions: Grouping for ListView command set</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 20 May 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/guidozam/new-feature-for-spfx-extensions-grouping-for-listview-command-set-4ck2</link>
      <guid>https://dev.to/guidozam/new-feature-for-spfx-extensions-grouping-for-listview-command-set-4ck2</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The new version 1.23 of the SharePoint Framework brings a couple of new features, one of those features is the introduction of grouping for the ListView command set.&lt;/p&gt;

&lt;p&gt;In this post I want to cover how this new functionality works and displays and to do this I’ve created a sample solution that you can find &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/ListView%20command%20sets/command-set-grouping" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Appearance
&lt;/h2&gt;

&lt;p&gt;Starting with the visual appearance of the grouping feature, following here’s how the grouping appears in a 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%2F51o7fvjwa49yjs4kxjoi.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%2F51o7fvjwa49yjs4kxjoi.png" width="798" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s zoom a little bit to better see how the grouping 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%2F1u3dzyvbs94x3aywhsmn.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%2F1u3dzyvbs94x3aywhsmn.png" width="508" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above screenshot the options &lt;code&gt;Hardware Management&lt;/code&gt; and &lt;code&gt;Software Management&lt;/code&gt; are groups (with custom icons) that contains other options. For example, in the &lt;code&gt;Hardware Management&lt;/code&gt; group there are other three 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%2Flp1vddk9ffnbuadu256v.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%2Flp1vddk9ffnbuadu256v.png" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Software Management&lt;/code&gt; group, on the other side, there are a couple of simple options and another group &lt;code&gt;User Support&lt;/code&gt; to demonstrate that it’s possible to have nested groups.&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%2Fjfb5u9zgfjajhyqayb76.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%2Fjfb5u9zgfjajhyqayb76.png" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have an idea of the visual appearance let’s cover how to achieve that.&lt;/p&gt;

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

&lt;p&gt;After covering the visual appearance, let’s cover the code that allows us developers to group the command set items.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I won’t cover how to create a ListView command set here, if you’re interested in knowing how to create a basic extension you can have a look &lt;a href="https://iamguidozam.blog/2024/11/06/how-to-create-your-first-spfx-listview-command-set-extension/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When defining a command, in the extension’s manifest, the structure is like the following:&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="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"SAMPLE_COMMAND"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sample command"&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;""&lt;/span&gt;&lt;span class="err"&gt;iconImageUrl&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;omitted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;brevity&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;",
  "&lt;/span&gt;&lt;span class="err"&gt;type&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;command&lt;/span&gt;&lt;span class="s2"&gt;"
},
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the newly inserted property &lt;code&gt;group&lt;/code&gt;, it’s possible to define that a command belongs to a specific group. For example, the previous example can become the following:&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="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"SAMPLE_COMMAND"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sample command"&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="nl"&gt;"iconImageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;omitted for brevity&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PARENT_GROUP"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&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 &lt;code&gt;PARENT_GROUP&lt;/code&gt;value is the actual name of the group.&lt;/p&gt;

&lt;p&gt;In order to define that a command is a group instead of a simple command, it’s enough to change the value of the &lt;code&gt;type&lt;/code&gt; property to &lt;code&gt;group&lt;/code&gt; instead of &lt;code&gt;command&lt;/code&gt;, for example:&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="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"SAMPLE_GROUP"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sample group"&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="nl"&gt;"iconImageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;omitted for brevity&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"group"&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;If you don’t want to check the sample solution on GitHub but still want to have a better view of how this grouping works, here are the commands and groups I’ve used:&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="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"items"&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="nl"&gt;"HARDWARE_GROUP"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hardware Management"&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="nl"&gt;"iconImageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;omitted for brevity&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"group"&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="nl"&gt;"SOFTWARE_GROUP"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Software Management"&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="nl"&gt;"iconImageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;omitted for brevity&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"group"&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="nl"&gt;"SUPPORT_SUBGROUP"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User Support"&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="nl"&gt;"iconImageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;omitted for brevity&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SOFTWARE_GROUP"&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="nl"&gt;"INSTALL_HARDWARE"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Install Hardware"&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="nl"&gt;"iconImageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;omitted for brevity&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HARDWARE_GROUP"&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="nl"&gt;"RETIRE_HARDWARE"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Retire Hardware"&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="nl"&gt;"iconImageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;omitted for brevity&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HARDWARE_GROUP"&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="nl"&gt;"REPAIR_REQUEST"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Request Repair"&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="nl"&gt;"iconImageUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;omitted for brevity&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HARDWARE_GROUP"&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="nl"&gt;"INSTALL_SOFTWARE"&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="nl"&gt;"title"&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="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Install Software"&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;iconImageUrl&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;omitted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;brevity&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;",
      "&lt;/span&gt;&lt;span class="err"&gt;type&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;command&lt;/span&gt;&lt;span class="s2"&gt;",
      "&lt;/span&gt;&lt;span class="err"&gt;group&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;SOFTWARE_GROUP&lt;/span&gt;&lt;span class="s2"&gt;"
    },
    "&lt;/span&gt;&lt;span class="err"&gt;UPDATE_SOFTWARE&lt;/span&gt;&lt;span class="s2"&gt;": {
      "&lt;/span&gt;&lt;span class="err"&gt;title&lt;/span&gt;&lt;span class="s2"&gt;": { "&lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;Update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Software&lt;/span&gt;&lt;span class="s2"&gt;" },
      "&lt;/span&gt;&lt;span class="err"&gt;iconImageUrl&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;omitted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;brevity&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;",
      "&lt;/span&gt;&lt;span class="err"&gt;type&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;command&lt;/span&gt;&lt;span class="s2"&gt;",
      "&lt;/span&gt;&lt;span class="err"&gt;group&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;SOFTWARE_GROUP&lt;/span&gt;&lt;span class="s2"&gt;"
    },
    "&lt;/span&gt;&lt;span class="err"&gt;CREATE_TICKET&lt;/span&gt;&lt;span class="s2"&gt;": {
      "&lt;/span&gt;&lt;span class="err"&gt;title&lt;/span&gt;&lt;span class="s2"&gt;": { "&lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;Create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Support&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ticket&lt;/span&gt;&lt;span class="s2"&gt;" },
      "&lt;/span&gt;&lt;span class="err"&gt;iconImageUrl&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;omitted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;brevity&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;",
      "&lt;/span&gt;&lt;span class="err"&gt;type&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;command&lt;/span&gt;&lt;span class="s2"&gt;",
      "&lt;/span&gt;&lt;span class="err"&gt;group&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;SUPPORT_SUBGROUP&lt;/span&gt;&lt;span class="s2"&gt;"
    },
    "&lt;/span&gt;&lt;span class="err"&gt;REMOTE_ASSIST&lt;/span&gt;&lt;span class="s2"&gt;": {
      "&lt;/span&gt;&lt;span class="err"&gt;title&lt;/span&gt;&lt;span class="s2"&gt;": { "&lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;Remote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Assistance&lt;/span&gt;&lt;span class="s2"&gt;" },
      "&lt;/span&gt;&lt;span class="err"&gt;iconImageUrl&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;omitted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;brevity&amp;gt;&lt;/span&gt;&lt;span class="s2"&gt;",
      "&lt;/span&gt;&lt;span class="err"&gt;type&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;command&lt;/span&gt;&lt;span class="s2"&gt;",
      "&lt;/span&gt;&lt;span class="err"&gt;group&lt;/span&gt;&lt;span class="s2"&gt;": "&lt;/span&gt;&lt;span class="err"&gt;SUPPORT_SUBGROUP&lt;/span&gt;&lt;span class="s2"&gt;"
    }
  }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The new grouping feature brings a more organized and intuitive experience to the ListView command set. By enabling items to be grouped, the command set becomes more flexible and user-friendly.&lt;/p&gt;

&lt;p&gt;If you want to know more about this topic have a look at the official documentation &lt;a href="https://learn.microsoft.com/en-us/sharepoint/dev/spfx/extensions/guidance/list-view-command-set-grouping" 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>listviewcommandset</category>
      <category>grouping</category>
    </item>
    <item>
      <title>Create your first declarative agent the pro-code way with VSCode</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 06 May 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/guidozam/create-your-first-declarative-agent-the-pro-code-way-with-vscode-pfe</link>
      <guid>https://dev.to/guidozam/create-your-first-declarative-agent-the-pro-code-way-with-vscode-pfe</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Nowadays Microsoft Copilot is THE argument when it comes to the Microsoft tenants, moreover we’re seeing an increase about using agents. Due to this I think it would be a good idea to start covering Copilot and I want to start with a Declarative Agent and since I’m a developer I want to start with the pro-code way of creating one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you’re interested in having a look at the code, you can find it &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/agents/Rubber%20duck" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What we’re building
&lt;/h2&gt;

&lt;p&gt;What I want to cover with this post is a Declarative Agent the pro-code way. All the developers should have their own rubber duck sitting on the desk, but in this times it can be a little “old school” to have one, so in this example I want to create a virtual one!&lt;/p&gt;

&lt;p&gt;The agent will be displaying 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%2Flj4c9wl0rsa96l3ndk35.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%2Flj4c9wl0rsa96l3ndk35.png" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user can interact with it asking questions like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am facing an issue in my SPFx solution that I cannot understand&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent will help the user understanding the issue and reaching a solution without explicitly giving the answer to the issue:&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%2Fuqa3o25xnbbrfgtl6yy0.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%2Fuqa3o25xnbbrfgtl6yy0.png" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is just a sample, I know there are quicker ways to resolve issues or understanding why things are not working as expected, but again this is a sample and the actual rubber ducks don’t even reply to developers &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%2Fblpugpmrvvjya7vguw46.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%2Fblpugpmrvvjya7vguw46.png" alt="😉" width="72" height="72"&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;In order to create the Declarative Agent you will need a couple of things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Microsoft tenant.&lt;/li&gt;
&lt;li&gt;VSCode, which you can find &lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The Microsoft 365 Agents Toolkit extension for VSCode, which you can find &lt;a href="https://marketplace.visualstudio.com/items?itemName=TeamsDevApp.ms-teams-vscode-extension" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;This blog post is not about how to setup the environment, but if you’re interested in knowing more you can have a look &lt;a href="https://microsoft.github.io/copilot-camp/pages/custom-engine/agents-sdk/00-prerequisites/" rel="noopener noreferrer"&gt;here&lt;/a&gt; skipping the Azure section and installing the extension for VSCode.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you search, in the extension panel of VSCode, for “Microsoft 365 Agents Toolkit”, you will find the following extension to install:&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%2Fdn7ou4yzq504cpqclhwc.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%2Fdn7ou4yzq504cpqclhwc.png" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After installing the extension, if you open it, you will see the following panel:&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%2Fp5mfe5wivcotc047dnxd.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%2Fp5mfe5wivcotc047dnxd.png" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From here you can start developing your Declarative Agent in the pro-code fashion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the agent
&lt;/h3&gt;

&lt;p&gt;To create a Declarative Agent with ATK (Microsoft 365 Agents Toolkit), you will have to open a new instance of VSCode, select the extension and click the “Create a New Agent/App” button shown in 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%2Fej2o12ne61t75e02ogmm.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%2Fej2o12ne61t75e02ogmm.png" width="584" height="674"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on the button will open a menu from the command palette where you can select what kind of agent or app you want to build:&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%2Fbbdhns9g00z8de290dok.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%2Fbbdhns9g00z8de290dok.png" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this sample we are using the “Declarative Agent” option, clicking on that option a new menu will open asking how you want to configure your agent:&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%2Fzrgnawgqlittvfnfb12a.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%2Fzrgnawgqlittvfnfb12a.png" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This Declarative Agent is not relying on any action or connector, so here simply select the “No Action” option. After specifying the option you are prompted to specify the name of the agent, in this case it will be “Rubber duck”:&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%2Frnaufh4shhmabtmgbtgj.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%2Frnaufh4shhmabtmgbtgj.png" width="800" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, you will be prompted for where you want to store your agent.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep in mind that you will be selecting the folder where the root folder of your agent will be created.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After selecting the root folder the solution will be scaffolded and a new instance of VSCode will be opened in that location.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution structure
&lt;/h3&gt;

&lt;p&gt;The created solution will have a structure 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%2F466un7n6pcflfdg49ev7.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%2F466un7n6pcflfdg49ev7.png" width="598" height="784"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;appPackage&lt;/code&gt; folder includes the Teams application manifest and the GPT manifest, in the sample we have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;manifest.json&lt;/code&gt;: the manifest of the Teams application that defines the metadata of the declarative agent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;declarativeAgent.json&lt;/code&gt;: defines the behaviour and configurations of the declarative agent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;instruction.txt&lt;/code&gt;: the actual system prompt for the declarative agent, this is used inside the &lt;code&gt;declarativeAgent.json&lt;/code&gt; file instead of writing the full prompt directly into the JSON file.&lt;/li&gt;
&lt;li&gt;color and outline PNGs: those are the icons for the agent, keep in mind that:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;color.png&lt;/code&gt;: a square coloured image of 192×192 pixels.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outline.png&lt;/code&gt;: a square outlined image of 32×32 pixels.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;env&lt;/code&gt; folder contains the environment files used to configure the declarative agent for each specific environment.&lt;/p&gt;

&lt;p&gt;One last thing that deserves a mention are the &lt;code&gt;yml&lt;/code&gt; files, those files are the main Teams Toolkit (the former name of the Microsoft Agents Toolkit) project files, each is for a specific environment. The main content of the project files are properties and configuration stage definitions.&lt;/p&gt;

&lt;h4&gt;
  
  
  declarativeAgent.json
&lt;/h4&gt;

&lt;p&gt;The main file for this example is the &lt;code&gt;declarativeAgent.json&lt;/code&gt; this contains the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;: this will be the name of the agent. By default this comes with a suffix taken from the environment file and named &lt;code&gt;APP_NAME_SUFFIX&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt;: this contains the description for the agent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;instructions&lt;/code&gt;: this will contains the system prompt for the agent. The system prompt can be stored in an external file. By default the value is loaded from the &lt;code&gt;instruction.txt&lt;/code&gt; file, to achieve that the value is: &lt;code&gt;$[file('instruction.txt')]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the sample agent the file contains the following:&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="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&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://developer.microsoft.com/json-schemas/copilot/declarative-agent/v1.6/schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"v1.6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rubber duck${{APP_NAME_SUFFIX}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sample declarative agent that act as a rubber duck to help developers."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"instructions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$[file('instruction.txt')]"&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;h3&gt;
  
  
  Declarative Agent configuration
&lt;/h3&gt;

&lt;p&gt;Now let’s cover how the agent is configured and this means that, for this sample, we need to only write the system prompt for the rubber duck agent.&lt;/p&gt;

&lt;p&gt;As described in the previous section, the system prompt is defined in the &lt;code&gt;instruction.txt&lt;/code&gt; file, I won’t copy its content here, but let me explain a little bit its content.&lt;/p&gt;

&lt;p&gt;Core behaviour of the system prompt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Act as a patient listener guiding developers through problems&lt;/li&gt;
&lt;li&gt;Encourage step-by-step explanations and reflection&lt;/li&gt;
&lt;li&gt;Ask open-ended questions instead of giving immediate solutions&lt;/li&gt;
&lt;li&gt;Help break complex problems into smaller parts&lt;/li&gt;
&lt;li&gt;Only give direct solutions if explicitly asked or user is stuck&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other sections of the system prompt includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Specific interaction style&lt;/li&gt;
&lt;li&gt;Narrow down issues with isolation and debugging techniques&lt;/li&gt;
&lt;li&gt;Don’t overwhelm with too many questions&lt;/li&gt;
&lt;li&gt;Keep responses concise and thoughtful&lt;/li&gt;
&lt;li&gt;Prefer guiding over explaining&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Building a Declarative Agent the pro-code way, using VSCode and the Microsoft Agent Toolkit, highlights the power of combining familiar development environments with a declarative approach to fully leverage Copilot’s capabilities. This approach also integrates seamlessly into existing development workflows allowing developers to store and manage agents within a source control system, making versioning, collaboration, and long-term maintenance significantly easier and more reliable.&lt;/p&gt;

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

</description>
      <category>githubcopilot</category>
      <category>declarativeagent</category>
      <category>ai</category>
    </item>
    <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://dev.to/guidozam/vscode-extension-node-version-pal-3779</link>
      <guid>https://dev.to/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&amp;nbsp;&lt;strong&gt;Node Version Pal&lt;/strong&gt;&amp;nbsp;was created.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node Version Pal&lt;/strong&gt;&amp;nbsp;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&amp;nbsp;&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&amp;nbsp;&lt;code&gt;.nvmrc&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code&gt;.node-version&lt;/code&gt;&amp;nbsp;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&amp;nbsp;&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&amp;nbsp;&lt;code&gt;nvm&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&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&amp;nbsp;&lt;code&gt;.nvmrc&lt;/code&gt;&amp;nbsp;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&amp;nbsp;&lt;code&gt;.nvmrc&lt;/code&gt;&amp;nbsp;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&amp;nbsp;&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;&amp;nbsp;/&amp;nbsp;&lt;code&gt;Cmd+Shift+X&lt;/code&gt;)&lt;/li&gt;



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



&lt;li&gt;Click&amp;nbsp;&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;&amp;nbsp;&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://dev.to/guidozam/cannot-turn-on-power-automate-flow-redacted-error-847</link>
      <guid>https://dev.to/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://dev.to/guidozam/enable-sharepoint-ai-on-your-tenant-preview-3c72</link>
      <guid>https://dev.to/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://dev.to/guidozam/vscode-extension-spfx-version-pal-5hej</link>
      <guid>https://dev.to/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&amp;nbsp;&lt;strong&gt;SPFx Version Pal&lt;/strong&gt;&amp;nbsp;comes in.&lt;/p&gt;




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

&lt;p&gt;SPFx Version Pal&amp;nbsp;is a lightweight&amp;nbsp;VS Code extension&amp;nbsp;that displays the detected SharePoint Framework version of your current project right in the VS Code&amp;nbsp;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&amp;nbsp;&lt;code&gt;package.json&lt;/code&gt;&amp;nbsp;— including packages like&amp;nbsp;&lt;code&gt;@microsoft/sp-core-library&lt;/code&gt;,&amp;nbsp;&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&amp;nbsp;&lt;code&gt;package.json&lt;/code&gt;&amp;nbsp;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;&amp;nbsp;/&amp;nbsp;&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;&amp;nbsp;for&amp;nbsp;&lt;code&gt;package.json&lt;/code&gt;&amp;nbsp;files.&lt;/li&gt;



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



&lt;li&gt;
&lt;strong&gt;Extract the version&lt;/strong&gt;&amp;nbsp;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;&amp;nbsp;— always visible and always up to date as you work.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach means there’s&amp;nbsp;&lt;em&gt;no extra configuration&lt;/em&gt;&amp;nbsp;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&amp;nbsp;&lt;code&gt;package.json&lt;/code&gt;, search for SPFx packages, and interpret version strings manually. That might only take a minute — but&amp;nbsp;&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&amp;nbsp;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&amp;nbsp;Visual Studio Code.&lt;/li&gt;



&lt;li&gt;Open any SPFx project with a valid&amp;nbsp;&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&amp;nbsp;&lt;em&gt;simple but smart&lt;/em&gt;&amp;nbsp;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://dev.to/guidozam/discover-the-comboboxlistitempicker-control-from-the-pnp-reusable-react-controls-ioj</link>
      <guid>https://dev.to/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://dev.to/guidozam/vscode-extension-invisifolder-3me4</link>
      <guid>https://dev.to/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://dev.to/guidozam/discover-the-listitemcomment-control-from-the-pnp-reusable-react-controls-4hg0</link>
      <guid>https://dev.to/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://dev.to/guidozam/using-top-actions-to-configure-web-parts-in-a-spfx-solution-35hc</link>
      <guid>https://dev.to/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>
  </channel>
</rss>
