Using PropertyFieldListPicker in an SPFx Web Part

The PropertyFieldListPicker control from the PnP SPFx Property Controls library adds a SharePoint list and document library selector to the Web Part Property Pane.

Instead of manually entering a list title or GUID, the Web Part author can select an available list directly from the Property Pane.

The control supports:

  • Single-list selection
  • Multiple-list selection
  • Hidden-list filtering
  • Sorting by list title or ID
  • List validation
  • Excluding specific lists
  • Filtering by list template or content type
  • Returning either the list ID or an object containing the list ID, title, and URL

In this example, the Web Part allows the author to select one SharePoint list. The selected list ID is stored in the Web Part properties and passed to the React component.

Official documentation:

PropertyFieldListPicker – PnP SPFx Property Controls

The official documentation confirms that the control can operate as either a single-selection or multi-selection list picker. It also accepts string, string[], IPropertyFieldList, or IPropertyFieldList[] as its selected value.


Install the PnP Property Controls package

Run the following command inside the existing SPFx solution:

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

Restore the project dependencies:

npm install

Start the SPFx development server using Heft:

heft start

Import PropertyFieldListPicker

The control and its sorting enumeration are imported from the PropertyFieldListPicker module:

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

PropertyFieldListPickerOrderBy determines how the available lists are sorted in the picker.

The available options are:

PropertyFieldListPickerOrderBy.Id

and:

PropertyFieldListPickerOrderBy.Title

In this example, lists are sorted alphabetically by title.


Web Part properties

Add a property that stores the selected list ID:

export interface IPropertyFieldListPickerWpWebPartProps {
description: string;
lists: string | string[];
}

The property uses:

string | string[]

This allows the same property to support either single or multiple list selection.

With the current control configuration, only one list is selected, so the stored value will normally be a string containing the SharePoint list GUID.

Example:

4fcf3a87-39eb-48cb-a86b-c268c0bf19dd

Complete Web Part implementation

The following is the complete PropertyFieldListPickerWpWebPart.ts implementation:

import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
type IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import {
BaseClientSideWebPart
} from '@microsoft/sp-webpart-base';
import {
IReadonlyTheme
} from '@microsoft/sp-component-base';
import * as strings
from 'PropertyFieldListPickerWpWebPartStrings';
import PropertyFieldListPickerWp
from './components/PropertyFieldListPickerWp';
import {
IPropertyFieldListPickerWpProps
} from './components/IPropertyFieldListPickerWpProps';
import {
PropertyFieldListPicker,
PropertyFieldListPickerOrderBy
} from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
export interface IPropertyFieldListPickerWpWebPartProps {
description: string;
lists: string | string[];
}
export default class PropertyFieldListPickerWpWebPart
extends BaseClientSideWebPart<IPropertyFieldListPickerWpWebPartProps> {
private _isDarkTheme: boolean = false;
private _environmentMessage: string = '';
public render(): void {
const element:
React.ReactElement<IPropertyFieldListPickerWpProps> =
React.createElement(
PropertyFieldListPickerWp,
{
description: this.properties.description,
isDarkTheme: this._isDarkTheme,
environmentMessage: this._environmentMessage,
userDisplayName:
this.context.pageContext.user.displayName,
lists: this.properties.lists
}
);
ReactDom.render(element, this.domElement);
}
protected onInit(): Promise<void> {
return this._getEnvironmentMessage()
.then(message => {
this._environmentMessage = message;
});
}
private _getEnvironmentMessage(): Promise<string> {
if (!!this.context.sdks.microsoftTeams) {
return this.context.sdks.microsoftTeams.teamsJs.app
.getContext()
.then(context => {
let environmentMessage: string = '';
switch (context.app.host.name) {
case 'Office':
environmentMessage =
this.context.isServedFromLocalhost
? strings.AppLocalEnvironmentOffice
: strings.AppOfficeEnvironment;
break;
case 'Outlook':
environmentMessage =
this.context.isServedFromLocalhost
? strings.AppLocalEnvironmentOutlook
: strings.AppOutlookEnvironment;
break;
case 'Teams':
case 'TeamsModern':
environmentMessage =
this.context.isServedFromLocalhost
? strings.AppLocalEnvironmentTeams
: strings.AppTeamsTabEnvironment;
break;
default:
environmentMessage =
strings.UnknownEnvironment;
}
return environmentMessage;
});
}
return Promise.resolve(
this.context.isServedFromLocalhost
? strings.AppLocalEnvironmentSharePoint
: strings.AppSharePointEnvironment
);
}
protected onThemeChanged(
currentTheme: IReadonlyTheme | undefined
): void {
if (!currentTheme) {
return;
}
this._isDarkTheme = !!currentTheme.isInverted;
const {
semanticColors
} = currentTheme;
if (semanticColors) {
this.domElement.style.setProperty(
'--bodyText',
semanticColors.bodyText || null
);
this.domElement.style.setProperty(
'--link',
semanticColors.link || null
);
this.domElement.style.setProperty(
'--linkHovered',
semanticColors.linkHovered || null
);
}
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration():
IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description:
strings.PropertyPaneDescription
},
groups: [
{
groupName:
strings.BasicGroupName,
groupFields: [
PropertyPaneTextField(
'description',
{
label:
strings.DescriptionFieldLabel
}
),
PropertyFieldListPicker(
'lists',
{
label: 'Select a list',
selectedList:
this.properties.lists,
includeHidden: false,
orderBy:
PropertyFieldListPickerOrderBy.Title,
disabled: false,
onPropertyChange:
this.onPropertyPaneFieldChanged
.bind(this),
properties:
this.properties,
context:
this.context as any,
onGetErrorMessage:
(
value:
string | string[]
): string => {
if (
!value ||
(
Array.isArray(value) &&
value.length === 0
)
) {
return 'Please select a SharePoint list.';
}
return '';
},
deferredValidationTime: 0,
key:
'listPickerFieldId'
}
)
]
}
]
}
]
};
}
}

Property Pane group

The PropertyFieldListPicker is added to the groupFields collection of the Property Pane group:

groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyFieldListPicker('lists', {
// Control configuration
})
]
}
]

The first argument passed to the control is:

'lists'

This value must match the Web Part property name:

lists: string | string[];

When the user selects a list, the control updates:

this.properties.lists

PropertyFieldListPicker configuration

The control is configured as follows:

PropertyFieldListPicker('lists', {
label: 'Select a list',
selectedList: this.properties.lists,
includeHidden: false,
orderBy: PropertyFieldListPickerOrderBy.Title,
disabled: false,
onPropertyChange:
this.onPropertyPaneFieldChanged.bind(this),
properties: this.properties,
context: this.context as any,
onGetErrorMessage:
(value: string | string[]): string => {
if (
!value ||
(
Array.isArray(value) &&
value.length === 0
)
) {
return 'Please select a SharePoint list.';
}
return '';
},
deferredValidationTime: 0,
key: 'listPickerFieldId'
})

Understanding the control properties

label

label: 'Select a list'

Defines the label displayed above the picker.


selectedList

selectedList: this.properties.lists

Passes the currently selected list to the control.

This keeps the selected value visible when the Property Pane is reopened.


includeHidden

includeHidden: false

Prevents hidden SharePoint lists from appearing in the picker.

The default value documented by the control is true, so setting it explicitly to false limits the picker to visible lists and libraries.


orderBy

orderBy: PropertyFieldListPickerOrderBy.Title

Sorts the available lists by their title.

The control also supports sorting by list ID:

orderBy: PropertyFieldListPickerOrderBy.Id

disabled

disabled: false

Keeps the picker enabled.

The control could be disabled conditionally:

disabled: this.properties.disableListSelection

onPropertyChange

onPropertyChange:
this.onPropertyPaneFieldChanged.bind(this)

Connects the custom PnP control to the standard SPFx property change mechanism.

When the selected list changes, SPFx updates:

this.properties.lists

properties

properties: this.properties

Provides the complete Web Part properties object to the custom property control.

The PnP control uses this object to update the selected property value.


context

context: this.context as any

Provides the current SPFx Web Part context.

The control requires the context to access the current SharePoint site and retrieve its available lists and document libraries. The documented type is BaseComponentContext.

The as any cast is used here because some SPFx and PnP package combinations may contain duplicate Microsoft dependency versions, causing an otherwise compatible context object to produce a TypeScript type error.


Validating the list selection

The example uses onGetErrorMessage to require a list selection:

onGetErrorMessage:
(value: string | string[]): string => {
if (
!value ||
(
Array.isArray(value) &&
value.length === 0
)
) {
return 'Please select a SharePoint list.';
}
return '';
},

The callback supports both possible property formats:

string

and:

string[]

The first condition checks whether no value exists:

!value

The second condition checks whether the value is an empty array:

Array.isArray(value) && value.length === 0

When no list is selected, the control displays:

Please select a SharePoint list.

When the value is valid, the callback returns an empty string:

return '';

The official control documentation describes onGetErrorMessage as the callback used to provide a validation message and determine whether the selected input is valid.


Deferred validation

The example configures:

deferredValidationTime: 0

This means the validation callback can run immediately.

The control’s documented default validation delay is 200 milliseconds.

A delayed validation could be configured as follows:

deferredValidationTime: 500

Unique control key

key: 'listPickerFieldId'

Every custom Property Pane field requires a unique key.

This key allows React and the SPFx Property Pane infrastructure to identify the control correctly.


Passing the selected list to React

Inside the Web Part’s render method, the selected value is passed to the React component:

lists: this.properties.lists

Complete relevant section:

const element:
React.ReactElement<IPropertyFieldListPickerWpProps> =
React.createElement(
PropertyFieldListPickerWp,
{
description: this.properties.description,
isDarkTheme: this._isDarkTheme,
environmentMessage: this._environmentMessage,
userDisplayName:
this.context.pageContext.user.displayName,
lists: this.properties.lists
}
);

The React properties interface must include the same type:

export interface IPropertyFieldListPickerWpProps {
description: string;
isDarkTheme: boolean;
environmentMessage: string;
userDisplayName: string;
lists: string | string[];
}

Displaying the selected list ID

A basic React component can display the selected list value:

import * as React from 'react';
import {
IPropertyFieldListPickerWpProps
} from './IPropertyFieldListPickerWpProps';
const PropertyFieldListPickerWp:
React.FunctionComponent<
IPropertyFieldListPickerWpProps
> = props => {
const selectedLists: string[] =
Array.isArray(props.lists)
? props.lists
: props.lists
? [props.lists]
: [];
return (
<section>
<h2>PropertyFieldListPicker</h2>
<p>{props.description}</p>
<p>
<strong>User:</strong>{' '}
{props.userDisplayName}
</p>
<p>
<strong>Environment:</strong>{' '}
{props.environmentMessage}
</p>
<h3>Selected list ID</h3>
{selectedLists.length === 0 ? (
<p>No SharePoint list selected.</p>
) : (
<ul>
{selectedLists.map(
(listId: string) => (
<li key={listId}>
{listId}
</li>
)
)}
</ul>
)}
</section>
);
};
export default PropertyFieldListPickerWp;

The conversion to an array allows the component to handle both single and multiple selection values safely.


Enabling multiple-list selection

The control supports multiple selection through the multiSelect property:

multiSelect: true

The complete configuration could include:

PropertyFieldListPicker('lists', {
label: 'Select lists',
selectedList: this.properties.lists,
includeHidden: false,
orderBy: PropertyFieldListPickerOrderBy.Title,
multiSelect: true,
showSelectAll: true,
disabled: false,
onPropertyChange:
this.onPropertyPaneFieldChanged.bind(this),
properties: this.properties,
context: this.context as any,
onGetErrorMessage:
(value: string | string[]): string => {
if (
!value ||
(
Array.isArray(value) &&
value.length === 0
)
) {
return 'Please select at least one SharePoint list.';
}
return '';
},
deferredValidationTime: 0,
key: 'listPickerFieldId'
})

multiSelect is false by default. The showSelectAll option applies only when multiple selection is enabled.


Returning the list title and URL

By default, the picker normally stores the selected list ID.

The control can also return an object containing the list ID, title, and server-relative URL:

includeListTitleAndUrl: true

In that scenario, the Web Part property should use IPropertyFieldList instead of only string.

Example:

import {
IPropertyFieldList
} from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
export interface IPropertyFieldListPickerWpWebPartProps {
description: string;
lists: IPropertyFieldList;
}

The documented IPropertyFieldList interface includes:

id: string;
title?: string;
url?: string;

This is useful when the React component needs to display the list title or access its server-relative URL without making another request.


Filtering list types

The control can restrict the returned lists by using a SharePoint base template ID.

For example, document libraries use base template 101:

baseTemplate: 101

Example:

PropertyFieldListPicker('lists', {
label: 'Select a document library',
selectedList: this.properties.lists,
baseTemplate: 101,
includeHidden: false,
orderBy: PropertyFieldListPickerOrderBy.Title,
disabled: false,
onPropertyChange:
this.onPropertyPaneFieldChanged.bind(this),
properties: this.properties,
context: this.context as any,
onGetErrorMessage:
(value: string | string[]): string => {
if (
!value ||
(
Array.isArray(value) &&
value.length === 0
)
) {
return 'Please select a document library.';
}
return '';
},
deferredValidationTime: 0,
key: 'listPickerFieldId'
})

This configuration shows only document libraries instead of every available list type.


Excluding specific lists

Specific lists can be excluded by title or ID:

listsToExclude: [
'Site Assets',
'Style Library'
]

Example:

PropertyFieldListPicker('lists', {
label: 'Select a list',
selectedList: this.properties.lists,
includeHidden: false,
listsToExclude: [
'Site Assets',
'Style Library'
],
orderBy: PropertyFieldListPickerOrderBy.Title,
disabled: false,
onPropertyChange:
this.onPropertyPaneFieldChanged.bind(this),
properties: this.properties,
context: this.context as any,
onGetErrorMessage:
(value: string | string[]): string => {
if (
!value ||
(
Array.isArray(value) &&
value.length === 0
)
) {
return 'Please select a SharePoint list.';
}
return '';
},
deferredValidationTime: 0,
key: 'listPickerFieldId'
})

The control supports exclusions by either list title or list ID.


Final result

After adding the Web Part to a SharePoint page and opening the Property Pane, the author can:

  1. Enter the Web Part description.
  2. Open the list picker.
  3. Select an available SharePoint list.
  4. Receive a validation message when no list is selected.
  5. Save the selected list ID in the Web Part properties.
  6. Pass that value to the React component.

The PropertyFieldListPicker provides a better authoring experience than asking users to manually enter SharePoint list names or GUIDs.

It also creates a strong foundation for Web Parts that need to retrieve items, documents, columns, views, or metadata from a configurable SharePoint list.

Official reference

PropertyFieldListPicker – PnP SPFx Property Controls

Edvaldo Guimrães Filho Avatar

Published by