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:
- Enter the Web Part description.
- Open the list picker.
- Select an available SharePoint list.
- Receive a validation message when no list is selected.
- Save the selected list ID in the Web Part properties.
- 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.
