How to Add Custom Controls in SPFx Property Pane

When building SPFx web parts, the property pane is the primary way to let users configure how the web part behaves without touching any code. In one of our SharePoint Online projects, we needed to show list or library data directly on a modern page and still allow site owners to choose which list and how many items to display.

The best approach was to use SPFx custom property pane controls so users could pick a list or library, and then the web part would automatically render its data using PnP React controls.

In this step-by-step tutorial, you will learn how the default SPFx property pane works, how values flow from the pane into the web part, and then how to add PnP custom controls such as PropertyFieldListPicker to the property pane. Finally, you will see how to use the selected list ID in a React component to fetch list items via SPHttpClient and display them using the PnP ListView control.

Recently, one of my colleagues was working on a SharePoint site customization using SPFx. In this customization, we needed to add an SPFx web part to the SharePoint site page so people on the site can quickly see the latest details of a specific SharePoint list/library on the page itself, without navigating to each list in the site. We also needed to allow users to specify how many records they want to see in this web part.

The user could then select any list or library, and the web part would automatically show the default view of the selected list. To achieve this, we used custom controls in the SPFx property pane and passed the selected list/library to the web part. In this tutorial, you will see how to use custom controls in the SPFx web part property pane with a working example that displays list views.

Download Complete Solution

You can download the complete SPFx solution, unzip it, run npm i, and test it without changing any code. This helps you quickly understand how the custom property pane controls and PnP React controls are wired together

Note: This example uses lists and libraries from the current SharePoint site context; it does not cover cross-site list selection.

Scenario used in this demo

In this demo scenario:

  • An SPFx web part displays items from a SharePoint list or library on a modern SharePoint page.
  • The editor can pick the target list/library in the property pane using a custom list picker control.
  • The selected list’s data is fetched using SPHttpClient and rendered using the PnP ListView React control.

SPFx Web Part Property Pane Overview

In the image for the basic example, you can see that for this web part, the “Description” field is on the property pane. The text entered in that field is displayed in the web part.

We use the property pane to configure the web part by passing dynamic values from the pane to the web part. Before adding custom controls, let’s understand how the default property pane control works and how it passes its value to the web part.

Basically, we used this property pane to configure the webpart by passing the dynamic value to the webpart.

spfx property pane text field control

Before we start adding custom controls to the SPFx web part property pane, let’s first understand the default property pane control and how it passes its value to the web part. You should already know how to create an SPFx web part using the React framework.

Step 1: Check the manifest.json file

Once you have created the SPFx web part, open the manifest.json file.

The manifest.json file contains basic information about the web part such as:

  • Web part ID, alias, and componentType.
  • The preconfiguredEntries section, which has a properties object that holds the default values for the web part.

When you add new custom controls to the property pane, you can define their default values in the properties object inside preconfiguredEntries.

spfx property pane controls

When we add new custom controls to the property pane, we can define their default values here.

Step 2: Understand default PropertyPaneTextField

Now open the main web part .ts file. At the end of the class, you will find the getPropertyPaneConfiguration() method; this is where you configure property pane fields.

By default, there is a PropertyPaneTextField for the description. To use this control, you import it as shown below:

import {
  type IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-property-pane';
spfx property pane dropdown

This code adds the description field to the web part property pane.

Step 3: Create props to pass values to React

To display the text entered in the description field in the property pane inside the web part, you need to create a prop and pass it to the React component. You will find the code below in the Props.ts file.

export interface IPropertyPaneDemoProps {
  description: string;
  isDarkTheme: boolean;
  environmentMessage: string;
  hasTeamsContext: boolean;
  userDisplayName: string;
}

Here, you define all the props that you want to send to the React component. For the description field in the property pane, you created a description prop in the IPropertyPaneDemoProps interface.

Step 4: Pass props from web part to React component

Now import the props into the main web part .ts file and pass them through the render() method to the React component.

In the render() method, you have something like:

propertypanetextfield spfx

Here description: this.properties.description means:

  • description = The prop defined in IPropertyPaneDemoProps.
  • this.properties.description = The value of the “description” field from the property pane, stored in the web part’s properties object.

this refers to the current web part instance, and properties is the object that holds all values coming from the property pane.

Step 5: Use props in the React component

Open the .tsx file for the React component. This component uses IPropertyPaneDemoProps so it can receive the values coming from the property pane.

At the top of the render() method, the props are unpacked:

 const {
      description,
      isDarkTheme,
      environmentMessage,
      hasTeamsContext,
      userDisplayName
    } = this.props;

This lets the component use the values directly. Inside the JSX, the description is displayed exactly as typed in the property pane.

webpart property pane text field spfx

Now that you understand how default values are passed between the property pane and the web part, let’s see how to add a custom control to the property pane in SPFx.

Add Custom Controls to SPFx Web Part Property Pane

In the example below, you can see that I added the PropertyFieldListPicker control in the web part property pane, which auto-populates SharePoint lists and libraries in the current site. Once you select the list or library, the data is displayed in the web part.

Here, we use the PnP ListView control to display data for the fields Title, ID, Created, Modified, Created By, and Modified By. You can see the screenshot below:

add pnp property pane controls in spfx web part

Follow the steps below to achieve this!

Step 1: Install PnP Property Controls

Run the command below in the command prompt at the root of your SPFx solution

npm install @pnp/spfx-property-controls --save --save-exact

This installs the PnP Property Pane field controls used in the SPFx web part property pane.

Step 2: Install PnP React Controls

Next, run the command below to install PnP React controls for SPFx.

npm install @pnp/spfx-controls-react --save --save-exact

These controls provide the ListView React component that you will use to display list items in the web part.

Step 3: Update web part properties interface

Open the main web part .ts file and add a new property for the selected list ID.

export interface IPropertyPaneDemoWebPartProps {
  description: string;
  selectedListId: string;
}

This selectedListId property will store the GUID of the selected list or library from the property pane.

Step 4: Import PropertyFieldListPicker

Add the import for PropertyFieldListPicker in the same web part .ts file:

import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';

This allows you to use the PnP list picker control in the property pane.

Step 5: Configure PropertyFieldListPicker in getPropertyPaneConfiguration

Update the getPropertyPaneConfiguration() method with the following code.

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          header: {
            description: strings.PropertyPaneDescription
          },
          groups: [
            {
              groupName: strings.BasicGroupName,
              groupFields: [
                PropertyPaneTextField('description', {
                  label: strings.DescriptionFieldLabel
                }),
                PropertyFieldListPicker('selectedListId', {
                label: 'Select a List or Library',
                selectedList: this.properties.selectedListId,
                includeHidden: false,
                orderBy: PropertyFieldListPickerOrderBy.Title,
                disabled: false,
                properties: this.properties,
                onPropertyChange: this.onPropertyPaneFieldChanged.bind(this),
                context: this.context,
                key: 'listPickerFieldId'
              })
              ]
            }
          ]
        }
      ]
    };
  }

Here, we added the PropertyFieldListPicker control with the following key options:

  • selectedListId = The property where the selected list’s ID (GUID) will be saved.
  • label = The text shown above the control to describe its purpose.
  • selectedList = Sets the currently selected list when the property pane loads.
  • includeHidden = Specifies whether hidden SharePoint lists should be shown.
  • orderBy = Defines how the list options should be sorted in the dropdown. Here, based on the title, it is ordered.
  • disabled = Enables or disables the control.
  • properties = Passes all web part properties so the control can update them
  • onPropertyChange =Triggers whenever the user selects a new list.
  • context = Provides the SharePoint context required to fetch lists.
  • key = A unique identifier for this control inside the property pane.

Step 6: Update Props.ts with selectedListId and context

Update the Props.ts file as shown below:

import { WebPartContext } from "@microsoft/sp-webpart-base";
export interface IPropertyPaneDemoProps {
  description: string;
  selectedListId: string;
  isDarkTheme: boolean;
  environmentMessage: string;
  hasTeamsContext: boolean;
  userDisplayName: string;
 context: WebPartContext 
}

Here, selectedListId is added to the existing props, and context is added so the React component can use the web part context to call SharePoint APIs.

Step 7: Pass selectedListId and context from web part to React

Open the main web part .ts file again and update the render() method:

public render(): void {
    const element: React.ReactElement<IPropertyPaneDemoProps> = React.createElement(
      PropertyPaneDemo,
      {
        description: this.properties.description,
        selectedListId: this.properties.selectedListId,
        isDarkTheme: this._isDarkTheme,
        environmentMessage: this._environmentMessage,
        hasTeamsContext: !!this.context.sdks.microsoftTeams,
        userDisplayName: this.context.pageContext.user.displayName,
        context: this.context
      }
    );
    ReactDom.render(element, this.domElement);
  }

Here, selectedListId: this.properties.selectedListId passes the selected list or library ID to the React component.

add property pane controls to spfx webpart

Step 8: Implement the React component with ListView

Update the .tsx React component file with the following code:

import * as React from "react";
import styles from "./PropertyPaneDemo.module.scss";
import type { IPropertyPaneDemoProps } from "./IPropertyPaneDemoProps";
import { escape } from "@microsoft/sp-lodash-subset";
import {
  ListView,
  IViewField,
  SelectionMode,
} from "@pnp/spfx-controls-react/lib/ListView";
export interface IPropertyPaneDemoState {
  items: any[];
}
import { SPHttpClient, SPHttpClientResponse } from "@microsoft/sp-http";

export default class PropertyPaneDemo extends React.Component<IPropertyPaneDemoProps,IPropertyPaneDemoState> {
  constructor(props: IPropertyPaneDemoProps) {
    super(props);
    this.state = {
      items: [],
    };
  }
  private _loadListItems(): void {
    if (!this.props.selectedListId) {
      this.setState({ items: [] });
      return;
    }

    const url = `${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists(guid'${this.props.selectedListId}')/items?$select=*,Author/Title,Editor/Title&$expand=Author,Editor`;

    this.props.context.spHttpClient
      .get(url, SPHttpClient.configurations.v1)
      .then((response: SPHttpClientResponse) => response.json())
      .then((data) => {
        this.setState({ items: data.value });
      });
  }

  public componentDidMount(): void {
    this._loadListItems();
  }

  public componentDidUpdate(prevProps: IPropertyPaneDemoProps): void {
    if (prevProps.selectedListId !== this.props.selectedListId) {
      this._loadListItems();
    }
  }
  private viewFields: IViewField[] = [
    {
      name: "Title",
      displayName: "Title",
      isResizable: true,
      sorting: true,
    },
    {
      name: "Id",
      displayName: "ID",
      isResizable: true,
    },
    {
      name: "Created",
      displayName: "Created",
      isResizable: true,
      sorting: true,
    },
    {
      name: "Modified",
      displayName: "Modified",
      isResizable: true,
      sorting: true,
    },
    {
      name: "Author.Title",
      displayName: "Created By",
      isResizable: true,
    },
    {
      name: "Editor.Title",
      displayName: "Modified By",
      isResizable: true,
    },
  ];

  public render(): React.ReactElement<IPropertyPaneDemoProps> {
    const { description, isDarkTheme, hasTeamsContext, userDisplayName } =
      this.props;

    return (
      <section
        className={`${styles.propertyPaneDemo} ${
          hasTeamsContext ? styles.teams : ""
        }`}
      >
        <div className={styles.welcome}>
          <img
            alt=""
            src={
              isDarkTheme
                ? require("../assets/welcome-dark.png")
                : require("../assets/welcome-light.png")
            }
            className={styles.welcomeImage}
          />

          <h2>Hello, {escape(userDisplayName)}!</h2>

          <div>
            Description: <strong>{escape(description)}</strong>
          </div>
        </div>

        {/* List View Below */}
        <div style={{ marginTop: "20px" }}>
          <ListView
            items={this.state.items}
            viewFields={this.viewFields}
            compact={true}
            selectionMode={SelectionMode.none}
            showFilter={true}
          />
        </div>
      </section>
    );
  }
}

In this React component:

  • ListView is imported from @pnp/spfx-controls-react/lib/ListView, and SPHttpClient from @microsoft/sp-http to fetch SharePoint list items.
  • IPropertyPaneDemoState holds items, which stores the SharePoint list items.
  • In the constructor(), the state is initialized with an empty array.
  • _loadListItems() loads SharePoint list data using SPHttpClient and updates the items state.
  • If selectedListId is empty, the items state is reset to an empty array.
  • componentDidMount() calls _loadListItems() when the web part loads.
  • componentDidUpdate() runs when props change and reloads items if the selected list has changed.
  • viewFields defines the columns displayed in the ListView (Title, ID, Created, Modified, Created By, Modified By).
  • In render(), the ListView is rendered with items, viewFields, compact mode, no selection, and a filter textbox.

Step 9: Test the SPFx web part

Run the gulp serve command. It will open the local or hosted SharePoint Workbench in the browser:

  • Add the web part to the page.
  • Open the property pane and select a list or library using the PropertyFieldListPicker control.
  • The list items will be displayed in the SPFx web part using the PnP ListView control.
pnp property pane controls in spfx web part

This way, we can easily add custom controls to the SPFx web part property pane.

Conclusion

This is how you can add custom controls to the SPFx web part property pane and use them to build powerful, configurable web parts. In this tutorial, you saw an overview of the property pane, how default controls work, and a complete example using PnP Property Pane controls and PnP React controls to retrieve lists and libraries from the current SharePoint site and dynamically display the selected list/library’s data in the web part.

Download the solution, unzip it, run npm i, and test it once; there is no need to update any code. Do let me know in the comments if you face any issues.

Also, you may like the following SPFx tutorials:

Power Apps functions free pdf

30 Power Apps Functions

This free guide walks you through the 30 most-used Power Apps functions with real business examples, exact syntax, and results you can see.

Download User registration canvas app

DOWNLOAD USER REGISTRATION POWER APPS CANVAS APP

Download a fully functional Power Apps Canvas App (with Power Automate): User Registration App