Exercise - Use the SPFx PnP reusable property pane controls

Completed

In this exercise, you'll learn how to use existing third-party controls from the popular PnP SPFx Reusable Property Pane Controls project.

Prerequisites

Important

In most cases, installing the latest version of the following tools is the best option. The versions listed here were used when this module was published and last tested.

Create a new SharePoint Framework solution and web part

Open a command prompt and change to the folder where you want to create the project.

Run the SharePoint Framework Yeoman generator by executing the following command:

yo @microsoft/sharepoint

Use the following to complete the prompt that is displayed (if more options are presented, accept the default answer):

  • What is your solution name?: HelloPnPControls
  • Which type of client-side component to create?: WebPart
  • What is your Web part name?: HelloPnPControls
  • Which template would you like to use?: No framework

After provisioning the folders required for the project, the generator will install all the dependency packages using npm.

Install the PnP SPFx reusable property pane controls

Open a command prompt and change to the folder for the root of the project. Execute the following command to install the controls:

npm install @pnp/spfx-property-controls -PE

Add the People Picker control to the web part

Open the project folder in Visual Studio Code.

Locate the web part class in the .\src\webparts\helloPnPControls\HelloPnPControlsWebPart.ts file.

Within the web part class, add the following import statements to the top of the file after the existing import statements:

import {
  IPropertyFieldGroupOrPerson,
  PropertyFieldPeoplePicker,
  PrincipalType
} from '@pnp/spfx-property-controls/lib/PropertyFieldPeoplePicker';

Locate the interface IHelloPnPControlsWebPartProps after the import statements. Add the following property to the interface to store the people selected by the new control you're about to add to the property pane:

people: IPropertyFieldGroupOrPerson[];

Display the selected people

Locate the web part's render() method. Within this method, find the following lines in the HTML output:

<div>
  <h3>Welcome to SharePoint Framework!</h3>
  <p>
  The SharePoint Framework (SPFx) is a extensibility model for Microsoft Viva, Microsoft Teams and SharePoint. It's the easiest way to extend Microsoft 365 with automatic Single Sign On, automatic hosting and industry standard tooling.
  </p>
  <h4>Learn more about SPFx development:</h4>
    <ul class="${styles.links}">
      <li><a href="https://aka.ms/spfx" target="_blank">SharePoint Framework Overview</a></li>
      <li><a href="https://aka.ms/spfx-yeoman-graph" target="_blank">Use Microsoft Graph in your solution</a></li>
      <li><a href="https://aka.ms/spfx-yeoman-teams" target="_blank">Build for Microsoft Teams using SharePoint Framework</a></li>
      <li><a href="https://aka.ms/spfx-yeoman-viva" target="_blank">Build for Microsoft Viva Connections using SharePoint Framework</a></li>
      <li><a href="https://aka.ms/spfx-yeoman-store" target="_blank">Publish SharePoint Framework applications to the marketplace</a></li>
      <li><a href="https://aka.ms/spfx-yeoman-api" target="_blank">SharePoint Framework API reference</a></li>
      <li><a href="https://aka.ms/m365pnp" target="_blank">Microsoft 365 Developer Community</a></li>
    </ul>
</div>

Replace the lines you located with the following:

<div class="selectedPeople"></div>

Add the following code at the end of the render() method. If any people have been selected, this will display their full names and email addresses in the <div> element you just added to the rendering:

if (this.properties.people && this.properties.people.length > 0) {
  let peopleList: string = '';
  this.properties.people.forEach((person) => {
    peopleList = peopleList + `<li>${ person.fullName } (${ person.email })</li>`;
  });

  this.domElement.getElementsByClassName('selectedPeople')[0].innerHTML = `<ul>${ peopleList }</ul>`;
}

Add the property pane field control to the property pane

Locate the web part's getPropertyPaneConfiguration() method.

Within the groupFields array, add the following people picker field control. This will bind the field control to the people property previously added to the web part's properties:

PropertyFieldPeoplePicker('people', {
  label: 'Property Pane Field People Picker PnP Reusable Control',
  initialData: this.properties.people,
  allowDuplicate: false,
  principalType: [PrincipalType.Users, PrincipalType.SharePoint, PrincipalType.Security],
  onPropertyChange: this.onPropertyPaneFieldChanged,
  context: this.context as any, // eslint-disable-line @typescript-eslint/no-explicit-any
  properties: this.properties,
  deferredValidationTime: 0,
  key: 'peopleFieldId'
})

Configure the hosted workbench

Locate and open the file config/serve.json

In the serve.json file, locate the initialPage setting. It's currently configured with a placeholder URL.

"initialPage": "https://{tenantDomain}/_layouts/workbench.aspx",

The {tenantDomain} string is replaced automatically by the gulp serve task using an environment variable on your workstation. Set the environment variable SPFX_SERVE_TENANT_DOMAIN to the domain of your hosted SharePoint Online site you want to use for testing.

Start the local web server using the provided gulp serve task without the nobrowser switch. This will build the project, start a local web server, and load the hosted workbench at the URL configured in serve.json in combination with your environment variable.

Test the web part

The benefit of using the people picker control is that it contains the logic necessary to call the SharePoint APIs that list users and groups within the current site.

Start the project by executing gulp serve from the command line in the root of the project.

If you see this warning in the hosted workbench, switch back to the command prompt, wait for the reload subtask to finish executing, and then refresh the hosted workbench.

Screenshot of the gulp serve warning.

Add the web part to the page using the same process from the previous exercises.

Once the web part has been added to the page, open the property pane with the edit web part icon using the same process from the previous exercises. Use the input control to find and select a user from the current site as shown in the following figure:

Screenshot using the PnP Reusable controls.

Add the Collection Data control to the web part

Locate the web part class in the .\src\webparts\helloPnPControls\HelloPnPControlsWebPart.ts file.

Within the web part class, add the following import statements to the top of the file after the existing import statements:

import {
  PropertyFieldCollectionData,
  CustomCollectionFieldType
} from '@pnp/spfx-property-controls/lib/PropertyFieldCollectionData';

Locate the interface IHelloPnPControlsWebPartProps after the import statements. Add the following property to the interface to store the collection of data entered in the new control you're about to add to the property pane:

expansionOptions: any[]; // eslint-disable-line @typescript-eslint/no-explicit-any

Display the expansionOptions property data

Locate the web part's render() method and add the following immediately after the <div class="selectedPeople"></div> element that you added previously:

<div class="expansionOptions"></div>

Add the following code at the end of the render() method. If any regions have been added, this will display their names and associated comments in the <div> element you just added to the rendering:

if (this.properties.expansionOptions && this.properties.expansionOptions.length > 0) {
  let expansionOptions: string  = '';
  this.properties.expansionOptions.forEach((option) => {
    expansionOptions = expansionOptions + `<li>${ option.Region }: ${ option.Comment } </li>`;
  });
  if (expansionOptions.length > 0) {
    this.domElement.getElementsByClassName('expansionOptions')[0].innerHTML = `<ul>${ expansionOptions }</ul>`;
  }
}

Add the property pane field control to the property pane

Locate the web part's getPropertyPaneConfiguration() method.

Within the groupFields array, add the following field collection control. This will bind the field control to the expansionOptions property previously added to the web part's properties:

PropertyFieldCollectionData('expansionOptions', {
  key: 'collectionData',
  label: 'Possible expansion options',
  panelHeader: 'Possible expansion options',
  manageBtnLabel: 'Manage expansion options',
  value: this.properties.expansionOptions,
  fields: [
    {
      id: 'Region',
      title: 'Region',
      required: true,
      type: CustomCollectionFieldType.dropdown,
      options: [
        { key: 'Northeast', text: 'Northeast' },
        { key: 'Northwest', text: 'Northwest' },
        { key: 'Southeast', text: 'Southeast' },
        { key: 'Southwest', text: 'Southwest' },
        { key: 'North', text: 'North' },
        { key: 'South', text: 'South' }
      ]
    },
    {
      id: 'Comment',
      title: 'Comment',
      type: CustomCollectionFieldType.string
    }
  ]
})

Test the web part

If you stopped the local web server after adding the people picker control, start the project by executing gulp serve from the command line in the root of the project and add the web part to the page using the same process from the previous exercises. Otherwise, refresh the workbench.

Open the property pane with the edit web part icon using the same process from the previous exercises. Select the Manage expansion options button.

Enter a few values in the provided fields, then select Save.

Screenshot using the PnP Reusable controls - Property edit experience.

Notice the values entered are displayed within the web part:

Screenshot using the PnP Reusable controls - Rendering property settings.

Summary

In this exercise, you learned how to use existing third-party controls from the popular PnP SPFx reusable property pane controls project.

Test your knowledge

1.

What is required to use the PnP reusable property pane controls in a SharePoint Framework client-side web part project?

2.

Why are some of the controls in the PnP reusable property pane controls library called smart controls?