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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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




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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

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

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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


&lt;/li&gt;

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

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


&lt;/li&gt;

&lt;/ul&gt;

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

&lt;/div&gt;



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

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

&lt;/div&gt;



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

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

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

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

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

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

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

&lt;/div&gt;



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

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

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

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

&lt;/div&gt;



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

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

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

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

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

</description>
      <category>testing</category>
      <category>e2e</category>
      <category>mfa</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Copying Arrays in TypeScript: Spread vs Deep Linking</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 03 Dec 2025 10:00:00 +0000</pubDate>
      <link>https://dev.to/guidozam/copying-arrays-in-typescript-spread-vs-deep-linking-1ap</link>
      <guid>https://dev.to/guidozam/copying-arrays-in-typescript-spread-vs-deep-linking-1ap</guid>
      <description>&lt;p&gt;&lt;strong&gt;TLDR&lt;/strong&gt; : use the spread operator for arrays of non-object items, otherwise you need to copy the array breaking the deep link of the objects using, for example, &lt;code&gt;JSON.parse&lt;/code&gt; and &lt;code&gt;JSON.stringify&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you’re interested in knowing more keep reading!&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;With this post I want to remind (mostly to myself) that there are different ways of copy an array. Sometimes, the behavior can be odd, and then you suddenly realize that the problem was the way you copied the array!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I know, probably this is not an exciting article, but it might be helpful to someone.&lt;/p&gt;

&lt;p&gt;In the worst case scenario, I will read it myself in the future! &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%2F0pgybgxzccfz2us00ft0.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%2F0pgybgxzccfz2us00ft0.png" alt="😄" width="72" height="72"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’ve created a sample app project using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After some editing I’ve created a very &lt;del&gt;ugly&lt;/del&gt; helpful example of how to copy an array and the main difference between a simple array and a complex 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%2Fz8cual5y50ixmzz38v34.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%2Fz8cual5y50ixmzz38v34.png" width="800" height="727"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the first example, I’ve created a number array and in the second I’ve created an object array. The buttons will copy the source array to the destination array and then update an element of the destination array.&lt;/p&gt;

&lt;p&gt;The button &lt;code&gt;Copy with spread operator&lt;/code&gt;, as it states, the copy will be performed using the spread operator for both the source arrays:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
const tempArrayOfNumbers = [...sourceArrayOfNumbers];
tempArrayOfNumbers[2] = 100;
setDestinationArrayOfNumbers(tempArrayOfNumbers);

const tempArrayOfObjects = [...sourceArrayOfObjects];
tempArrayOfObjects[2].name = `${tempArrayOfObjects[2].name} - changed!`;
setDestinationArrayOfObjects(tempArrayOfObjects);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the spread operator will work fine with arrays that are not containing objects. In case the array contains objects, a deep link to the object reference is maintained so the arrays will be different but both will point to the same object reference for each item…long story short: if you update an object in the destination array also the relative object of the source array gets 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%2Fa3yi71iq1cxfrqqi9gli.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%2Fa3yi71iq1cxfrqqi9gli.png" width="480" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The button &lt;code&gt;Copy without deep linking&lt;/code&gt;, on the other hand, creates the copy using the technique of transforming the source array in a string using JSON and then parsing it back to an array of objects. In this way every reference will be lost and the updates on an item don’t reflect on the source item.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const tempArrayOfNumbers = JSON.parse(JSON.stringify(sourceArrayOfNumbers));
tempArrayOfNumbers[3] = 42;
setDestinationArrayOfNumbers(tempArrayOfNumbers);

const tempArrayOfObjects = JSON.parse(JSON.stringify(sourceArrayOfObjects));
tempArrayOfObjects[3].name = `${tempArrayOfObjects[3].name} - changed!`;
setDestinationArrayOfObjects(tempArrayOfObjects);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result will be 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%2F8hps92b9ux6m4maxhgnz.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%2F8hps92b9ux6m4maxhgnz.png" width="449" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to play with the sample you can find it &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/React/play-with-array-copy" rel="noopener noreferrer"&gt;here on GitHub&lt;/a&gt;.&lt;/p&gt;

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

</description>
      <category>dev</category>
      <category>array</category>
      <category>hint</category>
      <category>react</category>
    </item>
    <item>
      <title>Access is denied (0x80070005 (E_ACCESSDENIED)) while provisioning template with PnP PowerShell</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 29 Oct 2025 10:30:00 +0000</pubDate>
      <link>https://dev.to/guidozam/access-is-denied-0x80070005-eaccessdenied-while-provisioning-template-with-pnp-powershell-1hbm</link>
      <guid>https://dev.to/guidozam/access-is-denied-0x80070005-eaccessdenied-while-provisioning-template-with-pnp-powershell-1hbm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;By utilizing the PnP PowerShell module, users can harness the power of scripting to automate tasks, reduce manual errors, and manage SharePoint resources effectively.&lt;/p&gt;

&lt;p&gt;This approach not only saves time but also enhances consistency across different environments. Additionally, leveraging this powerful tool allows for customization options that can align with specific project requirements.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you’re interested in knowing more about PnP PowerShell, have a look at the official site &lt;a href="https://pnp.github.io/powershell/index.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To provision a site template with PnP PowerShell, you will have simply to invoke the correct command, for example the following one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invoke-PnPSiteTemplate -Path "Provisioning-template.xml"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this approach is a must go for, sometimes errors pop up, in fact today I’ve faced the following error:&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%2Fiamguidozam.blog%2Fwp-content%2Fuploads%2F2025%2F10%2Fimage-1.png%3Fw%3D768" 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%2Fiamguidozam.blog%2Fwp-content%2Fuploads%2F2025%2F10%2Fimage-1.png%3Fw%3D768" alt="The image represent a PowerShell terminal with the following text in red:&amp;lt;br&amp;gt;
Invoke-PnPSiteTemplate: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" width="768" height="25"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Invoke-PnPSiteTemplate: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, let’s cover how I faced this issue.&lt;/p&gt;
&lt;h2&gt;
  
  
  Debugging
&lt;/h2&gt;

&lt;p&gt;To understand what is happening, since the error is not friendly at all, I’ve enabled the trace logging. You can do this with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Set-PnPTraceLog -On -LogFile log.txt -Level Debug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, this command will save all the debugging logs to a file named &lt;code&gt;log.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This allowed me to scan the logs and finding out the following rows (cleaned up a little bit for better reading):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Debug] Updating field {GUID} in site

[PnP.Framework] [0] [Error] ExecuteQuery threw following exception: Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Turned out
&lt;/h2&gt;

&lt;p&gt;In my case, it turned out that the issue was generated by the field &lt;code&gt;_ExtendedDescription&lt;/code&gt; present in my template file.&lt;/p&gt;

&lt;p&gt;After banging my head on a wall for a while I understood what was happening.&lt;/p&gt;

&lt;p&gt;I discovered that the issue was generated from a setting of the SharePoint site, setting the &lt;code&gt;DenyAddAndCustomizePages&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; resolved the issue!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Set-PnPTenantSite -Url "&amp;lt;your site URL&amp;gt;" -DenyAddAndCustomizePages:$false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;It seems that the setting &lt;code&gt;DenyAddAndCustomizePages&lt;/code&gt; prevent updating some field so, if the next time you’re provisioning a site template with PnP PowerShell keep this in mind! I hope that this article helps you avoiding banging your head like I did! And if it’s not, let’s connect on socials and discuss your issue!&lt;/p&gt;

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

</description>
      <category>pnp</category>
      <category>tools</category>
      <category>errors</category>
      <category>powershell</category>
    </item>
    <item>
      <title>SPFx extensions: discover the field customizer</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 15 Oct 2025 09:00:00 +0000</pubDate>
      <link>https://dev.to/guidozam/spfx-extensions-discover-the-field-customizer-k3m</link>
      <guid>https://dev.to/guidozam/spfx-extensions-discover-the-field-customizer-k3m</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;SharePoint Framework offers different extension project types, for example the Application customizer (more &lt;a href="https://iamguidozam.blog/2024/05/29/spfx-extensions-discover-the-application-customizer/" rel="noopener noreferrer"&gt;here&lt;/a&gt;), those extensions allow customization of the standard SharePoint Online UI/UX. With this article I will cover the field customizer extension.&lt;/p&gt;

&lt;p&gt;This extension allows customizing the appearance of a specific field of a SharePoint Online list.&lt;/p&gt;

&lt;p&gt;To demonstrate the use of a simple field customizer I’ve created a sample solution that you can find &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/field%20customizers/base-field-customizer" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;First thing first, let’s see how the sample solution displays!&lt;/p&gt;

&lt;p&gt;Following, the list without the field customizer, pay attention to the &lt;code&gt;Done&lt;/code&gt; column which displays a percentage of completion:&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%2Filzvz2rwu2apdtb93lak.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%2Filzvz2rwu2apdtb93lak.png" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here with the field customizer in 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%2Fcj791a8o3abrra3k48q0.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%2Fcj791a8o3abrra3k48q0.png" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the numeric value is displayed as a a progress bar with a different color for different value ranges.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This is just a simple sample to demonstrate how to use this SPFx extension. The possible customizations can be way more complex than this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let’s cover how to achieve this!&lt;/p&gt;

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

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

&lt;p&gt;To create the solution, there are a couple of different methods, I will not cover those in detail here because it’s not the topic of this article, but those are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using the VSCode extension &lt;strong&gt;SharePoint Framework Toolkit&lt;/strong&gt;. This extension offers a very nice UI to allow the creation of the solution. You can find it &lt;a href="https://marketplace.visualstudio.com/items?itemName=m365pnp.viva-connections-toolkit" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;using &lt;strong&gt;Yeoman generator&lt;/strong&gt;. This is a CLI tool, if you prefer using command line tools. I wrote an introductory article about it a while ago, you can find it &lt;a href="https://iamguidozam.blog/2023/09/13/yeoman-generator-is-your-best-friend-for-an-spfx-project/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s see the code in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Field customizer highlights
&lt;/h3&gt;

&lt;p&gt;When the solution is created, the field customizer extension’s class extends the SPFx &lt;code&gt;BaseFieldCustomizer&lt;/code&gt;. The class signature will be like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default class BasicFieldCustomizerFieldCustomizer
  extends BaseFieldCustomizer&amp;lt;IBasicFieldCustomizerFieldCustomizerProperties&amp;gt; {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the class, the method used to define how the render of the field appears is the &lt;code&gt;onRenderCell&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;public onRenderCell(event: IFieldCustomizerCellEventParameters): void {
  // Retrieve the field value
  const percentage: unknown = event.fieldValue;

  const basicFieldCustomizer: React.ReactElement&amp;lt;IBasicFieldCustomizerProps&amp;gt; = React.createElement(BasicFieldCustomizer, 
{
  percentage
} as IBasicFieldCustomizerProps);

  ReactDOM.render(basicFieldCustomizer,
    event.domElement);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method will render the React component that will actually define how the field value will be rendered.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I will not cover the whole implementation of the &lt;code&gt;BasicFieldCustomizer&lt;/code&gt; here, let’s just say that it creates a &lt;code&gt;div&lt;/code&gt; element with a specific color based on the field value. If you’re interested in knowing more about the component you can check the code &lt;a href="https://github.com/GuidoZam/blog-samples/blob/main/field%20customizers/base-field-customizer/src/extensions/basicFieldCustomizer/components/BasicFieldCustomizer.tsx" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After updating the code as you need, the next thing to configure is the &lt;code&gt;serve.json&lt;/code&gt; file. This file is used for testing purposes and allows to define where to execute the tests.&lt;/p&gt;

&lt;p&gt;You can specify a custom configuration, if there is no need of a specific one you can configure the default one. For example, in the sample solution, I’m using the default configuration as following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"serveConfigurations": {
  "default": {
    "pageUrl":
      "https://{tenantDomain}/SitePages/myPage.aspx",
    "fieldCustomizers": {
      "Done": {
        "id": "c6305766-23e2-4fac-9bd2-fe9b80eb82de",
    "properties": {}
      }
    }
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important configurations here are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pageUrl&lt;/code&gt;: the URL of the page where you want to test your field customizer. The &lt;code&gt;{tenantDomain}&lt;/code&gt; placeholder is automatically overridden if you have specified the environment variable (more on that &lt;a href="https://learn.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-development-environment#set-the-spfx_serve_tenant_domain-environment-variable-optional" rel="noopener noreferrer"&gt;here&lt;/a&gt;), otherwise you can just copy and paste the full URL for the target page in the SharePoint Online site.&lt;/li&gt;
&lt;li&gt;Inside the &lt;code&gt;fieldCustomizers&lt;/code&gt; object, you need to &lt;strong&gt;create an object with the internal name of the field you’re customizing&lt;/strong&gt; and this object, inside the &lt;code&gt;id&lt;/code&gt; property, contains the id of the field customizer (which can be found in the field customizer manifest JSON file).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After configuring the &lt;code&gt;serve.json&lt;/code&gt; file, executing the following command will open a browser window that points to the &lt;code&gt;pageUrl&lt;/code&gt; specified in the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gulp serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the browser window opens, you will be asked to load or not the debug scripts:&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%2F1qvg86slskfpriis1j87.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%2F1qvg86slskfpriis1j87.png" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on the “Load debug scripts” button, the needed files are loaded and you should already see your field customizer in action!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hint: if the field customizer is not loading, try adding the following parameter to the query string:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;amp;allowSpfxDevFallback=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If the field customizer is still not loading, check that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;pageURL&lt;/code&gt; inside the &lt;code&gt;serve.json&lt;/code&gt; file is pointing to the correct page.&lt;/li&gt;
&lt;li&gt;The column internal name used in the &lt;code&gt;serve.json&lt;/code&gt; file is the same of the target SharePoint Online column and that the column is visible in the current view.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;id&lt;/code&gt; property of the field customizer object used in the &lt;code&gt;serve.json&lt;/code&gt; file is the same as the manifest JSON file of the field customizer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;The field customizer is another useful extension of the SharePoint Framework. It will enable developers to easily customize SharePoint Online and create useful and unique UI/UX.&lt;/p&gt;

&lt;p&gt;If you’re interested in discovering plenty of examples regarding the field customizer, have a look &lt;a href="https://pnp.github.io/sp-dev-fx-webparts/samples/type/" rel="noopener noreferrer"&gt;here&lt;/a&gt;, filter by “field customizer”, and enjoy the community work!&lt;/p&gt;

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

</description>
      <category>spfx</category>
      <category>fieldcustomizer</category>
      <category>extension</category>
      <category>react</category>
    </item>
    <item>
      <title>How to Use Image Helper API in SharePoint Framework</title>
      <dc:creator>Guido Zambarda</dc:creator>
      <pubDate>Wed, 01 Oct 2025 09:00:00 +0000</pubDate>
      <link>https://dev.to/guidozam/how-to-use-image-helper-api-in-sharepoint-framework-521o</link>
      <guid>https://dev.to/guidozam/how-to-use-image-helper-api-in-sharepoint-framework-521o</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The Image Helper API has been introduced with the version 1.14 of the SharePoint Framework and it allow to generate a URL to an image that will be close to requested site, this can be useful if resizing operations are required, and also the image might load faster because of caching. To use the Image Helper API the source image will have to be stored in SharePoint Online.&lt;/p&gt;

&lt;p&gt;Currently, if the requested width is not one of the supported values, the resulting image may be of a different dimension. The documentation states that the supported widths (in pixels) are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;200&lt;/li&gt;
&lt;li&gt;400&lt;/li&gt;
&lt;li&gt;960&lt;/li&gt;
&lt;li&gt;1600&lt;/li&gt;
&lt;li&gt;2560&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As usual, I’ve created a sample solution to demonstrate how the Image Helper API works, you can find it &lt;a href="https://github.com/GuidoZam/blog-samples/tree/main/web%20parts/image-helper-sample" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;The visual appearance of the solution is 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%2Fqvwsyigbf6e5ch4wslof.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%2Fqvwsyigbf6e5ch4wslof.png" width="598" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the top there’s a width selector with some default values, right after it there’s the PnP ImagePicker control. This control will help users selecting the images provided out-of-the-box or the ones from the SharePoint Online sites available to the user.&lt;/p&gt;

&lt;p&gt;The last section, will show the processed image and the resulting URL retrieved from the call to the &lt;code&gt;ImageHelper.convertToImageUrl&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;To show the result, here is an example with a default image that is resized to the 400px width:&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%2F6jsyyjbu1zrvndll0hty.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%2F6jsyyjbu1zrvndll0hty.png" width="800" height="728"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see the generated SharePoint URL contains many parameters and settings. For example, in the above screenshot, the URL has the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://&amp;lt;tenant&amp;gt;.sharepoint.com/_api/v2.1/shares/&amp;lt;drive id&amp;gt;/driveItem/thumbnails/0/c400x99999/content?prefer=noRedirect,extendCacheMaxAge&amp;amp;clientType=modernWebPart&amp;amp;format=webp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the URL, the section that is defining the size of the generated image is the &lt;code&gt;c400x99999&lt;/code&gt; string. This string specify to the API what’s the desired width and height of the image. The 400 value is the one specified via the dropdown of the sample solution, the 99999 value is specified because no desired height has been specified when calling the &lt;code&gt;convertToImageUrl&lt;/code&gt; function.&lt;/p&gt;

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

&lt;p&gt;To use the &lt;code&gt;convertToImageUrl&lt;/code&gt; method from the &lt;code&gt;ImageHelper&lt;/code&gt; class you will first have to import the SPFx package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { ImageHelper } from '@microsoft/sp-image-helper';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package should already be available when you create the solution, if that’s not the case you can install it with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @microsoft/sp-image-helper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To quickly allow the picture selection I’ve used the &lt;code&gt;ImagePicker&lt;/code&gt; from the PnP reusable React controls.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don’t know the PnP reusable React controls package already you can have a look at the official site &lt;a href="https://pnp.github.io/sp-dev-fx-controls-react/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To actually resize the image with the &lt;code&gt;ImageHelper&lt;/code&gt; class you can use the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ImageHelper.convertToImageUrl({ sourceUrl: imageUrl, width: selectedWidth })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method accepts an object where it’s possible to specify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sourceUrl&lt;/code&gt; of the original image, this is a required parameter.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;width&lt;/code&gt; representing the wanted image size, this is also a required parameter.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;height&lt;/code&gt; which is the desired image height, this is an optional parameter and is suggested, if possible, to avoid it for performance reasons.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The Image Helper API is an out-of-the-box functionality that may be of use if you need to show and resize images, that come from SharePoint Online, in your SharePoint Framework solution. It’s easy and straightforward to use. The only downside, in my opinion, is that not always the requested size is the final size of the image so be aware of this possibility.&lt;/p&gt;

&lt;p&gt;If you’re interested in knowing more about this you can check the official documentation &lt;a href="https://learn.microsoft.com/en-us/sharepoint/dev/spfx/image-helper-api" 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>react</category>
      <category>api</category>
    </item>
  </channel>
</rss>
