The PropertyFieldColumnPicker control allows users to select one or more columns from a SharePoint list or document library directly from the Web Part Property Pane.
Instead of requiring users to manually enter a SharePoint column name, the control retrieves the available columns from the selected list and displays them in a picker.
Using the PnP PropertyFieldColumnPicker Control in an SPFx Web Part
The PropertyFieldColumnPicker control allows users to select one or more columns from a SharePoint list or document library directly from the Web Part Property Pane.
Instead of requiring users to manually enter a SharePoint column name, the control retrieves the available columns from the selected list and displays them in a picker.
The control supports:
- Single-column selection
- Multiple-column selection
- Sorting columns by title or ID
- Returning the column title, ID, or internal name
- Excluding specific columns
- Displaying or hiding hidden SharePoint columns
- Rendering multiple selections as checkboxes or a multiselect dropdown
The control automatically retrieves the columns from the SharePoint list identified by the listId property. (Microsoft 365 Community)
Official documentation:
PropertyFieldColumnPicker — PnP SPFx Property Controls
Installing the PnP SPFx Property Controls
Run the following command from the root folder of the existing SPFx solution:
npm install @pnp/spfx-property-controls --save
After installing the package, restore the remaining project dependencies:
npm install
The official package import for this control is:
import { PropertyFieldColumnPicker, PropertyFieldColumnPickerOrderBy} from '@pnp/spfx-property-controls/lib/PropertyFieldColumnPicker';
The PnP documentation identifies PropertyFieldColumnPicker and PropertyFieldColumnPickerOrderBy as the primary imports required to add the control to an SPFx Property Pane. (Microsoft 365 Community)
How the Control Works
The control requires the ID of an existing SharePoint list or document library.
This value is provided through the listId property:
listId: this.properties.list
After receiving the list ID, the control retrieves the columns from that list and displays them in the Property Pane.
The selected value is then saved in the Web Part properties.
For a single-column picker, the selected value is stored as a string:
column: string;
For a multiple-column picker, the selected values are stored as an array:
multiColumn: string[];
The control officially supports both string and string[] through the selectedColumn property. (Microsoft 365 Community)
Web Part Properties
Open the Web Part file and define the following interface:
export interface IPropertyFieldColumnPickerWpWebPartProps { description: string; // Stores the SharePoint list or library ID list: string; // Stores the selected single column column: string; // Stores the selected multiple columns multiColumn: string[];}
The list property stores the GUID of the selected SharePoint list or library.
The column property stores the value returned by the single-column picker.
The multiColumn property stores all values returned by the multiple-column picker.
Complete Web Part Code
Replace the content of PropertyFieldColumnPickerWpWebPart.ts with the following code:
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 'PropertyFieldColumnPickerWpWebPartStrings';import PropertyFieldColumnPickerWp from './components/PropertyFieldColumnPickerWp';import { IPropertyFieldColumnPickerWpProps} from './components/IPropertyFieldColumnPickerWpProps';import { PropertyFieldColumnPicker, PropertyFieldColumnPickerOrderBy} from '@pnp/spfx-property-controls/lib/PropertyFieldColumnPicker';export interface IPropertyFieldColumnPickerWpWebPartProps { description: string; list: string; column: string; multiColumn: string[];}export default class PropertyFieldColumnPickerWpWebPart extends BaseClientSideWebPart< IPropertyFieldColumnPickerWpWebPartProps > { private _isDarkTheme: boolean = false; private _environmentMessage: string = ''; public render(): void { const element: React.ReactElement<IPropertyFieldColumnPickerWpProps> = React.createElement( PropertyFieldColumnPickerWp, { description: this.properties.description, isDarkTheme: this._isDarkTheme, environmentMessage: this._environmentMessage, userDisplayName: this.context.pageContext.user.displayName, list: this.properties.list, column: this.properties.column, multiColumn: this.properties.multiColumn || [] } ); ReactDom.render(element, this.domElement); } protected onInit(): Promise<void> { return this._getEnvironmentMessage() .then((message: string): void => { this._environmentMessage = message; }); } private _getEnvironmentMessage(): Promise<string> { if (this.context.sdks.microsoftTeams) { return this.context .sdks .microsoftTeams .teamsJs .app .getContext() .then((context): string => { switch (context.app.host.name) { case 'Office': return this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOffice : strings.AppOfficeEnvironment; case 'Outlook': return this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOutlook : strings.AppOutlookEnvironment; case 'Teams': case 'TeamsModern': return this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentTeams : strings.AppTeamsTabEnvironment; default: return strings.UnknownEnvironment; } }); } 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 } ), PropertyPaneTextField( 'list', { label: 'List or library ID', description: 'Enter the GUID of a SharePoint list or library' } ), PropertyFieldColumnPicker( 'column', { label: 'Select a column', context: this.context as any, selectedColumn: this.properties.column, listId: this.properties.list, disabled: !this.properties.list, orderBy: PropertyFieldColumnPickerOrderBy.Title, onPropertyChange: this .onPropertyPaneFieldChanged .bind(this), properties: this.properties, deferredValidationTime: 0, key: 'columnPickerFieldId', displayHiddenColumns: false, multiSelect: false } ), PropertyFieldColumnPicker( 'multiColumn', { label: 'Select multiple columns', context: this.context as any, selectedColumn: this.properties.multiColumn || [], listId: this.properties.list, disabled: !this.properties.list, orderBy: PropertyFieldColumnPickerOrderBy.Title, onPropertyChange: this .onPropertyPaneFieldChanged .bind(this), properties: this.properties, deferredValidationTime: 0, key: 'multiColumnPickerFieldId', displayHiddenColumns: false, multiSelect: true } ) ] } ] } ] }; }}
Understanding the Property Pane Group
The custom controls are added inside the groupFields array:
groupFields: [ PropertyPaneTextField(...), PropertyFieldColumnPicker(...), PropertyFieldColumnPicker(...)]
The first field stores the Web Part description.
The second field temporarily receives the GUID of the SharePoint list or library.
The third field displays the single-column picker.
The fourth field displays the multiple-column picker.
The controls are placed inside the Property Pane group:
{ groupName: strings.BasicGroupName, groupFields: [...]}
This means all configuration fields appear together in the same Property Pane section.
Single-Column Selection
The following configuration creates a picker that allows only one SharePoint column to be selected:
PropertyFieldColumnPicker( 'column', { label: 'Select a column', context: this.context as any, selectedColumn: this.properties.column, listId: this.properties.list, disabled: !this.properties.list, orderBy: PropertyFieldColumnPickerOrderBy.Title, onPropertyChange: this.onPropertyPaneFieldChanged.bind(this), properties: this.properties, deferredValidationTime: 0, key: 'columnPickerFieldId', displayHiddenColumns: false, multiSelect: false })
The first argument identifies the Web Part property that receives the selected value:
'column'
Therefore, when a user selects a column, the value is stored in:
this.properties.column
The multiSelect property is set to false, so the user can select only one column.
Single selection is also the default behavior when multiSelect is omitted. (Microsoft 365 Community)
Multiple-Column Selection
The following configuration allows the user to select multiple columns:
PropertyFieldColumnPicker( 'multiColumn', { label: 'Select multiple columns', context: this.context as any, selectedColumn: this.properties.multiColumn || [], listId: this.properties.list, disabled: !this.properties.list, orderBy: PropertyFieldColumnPickerOrderBy.Title, onPropertyChange: this.onPropertyPaneFieldChanged.bind(this), properties: this.properties, deferredValidationTime: 0, key: 'multiColumnPickerFieldId', displayHiddenColumns: false, multiSelect: true })
The selected values are stored in:
this.properties.multiColumn
Because multiple values can be selected, the property must be declared as an array:
multiColumn: string[];
The multiSelect property enables the multiple-column selection mode. By default, the control uses single selection. (Microsoft 365 Community)
Disabling the Picker Until a List Is Provided
The control uses the following expression:
disabled: !this.properties.list
This disables the column picker when the list property is empty.
As soon as a valid list or library ID is entered, the expression becomes false, and the column picker is enabled.
This prevents the control from attempting to retrieve columns without knowing which list should be queried.
Sorting the Columns
The following property sorts the available columns by title:
orderBy: PropertyFieldColumnPickerOrderBy.Title
The control supports the following official ordering options:
PropertyFieldColumnPickerOrderBy.Id
and:
PropertyFieldColumnPickerOrderBy.Title
Id sorts the results using the SharePoint column ID, while Title sorts them using the visible column title. (Microsoft 365 Community)
Displaying Hidden Columns
The following configuration prevents hidden SharePoint columns from appearing in the picker:
displayHiddenColumns: false
To include hidden columns, change the value to:
displayHiddenColumns: true
By default, hidden columns are not returned. (Microsoft 365 Community)
In most business scenarios, keeping this property set to false provides a cleaner selection experience.
Understanding selectedColumn
For the single-column control, the current value is passed using:
selectedColumn: this.properties.column
For multiple-column selection, the current values are passed using:
selectedColumn: this.properties.multiColumn || []
The fallback array prevents the component from receiving undefined before the user has selected any columns.
The official type accepted by selectedColumn is:
string | string[]
This allows the same PnP control to support both single and multiple selections. (Microsoft 365 Community)
React Component Properties
Create or update the following file:
src/webparts/propertyFieldColumnPickerWp/components/IPropertyFieldColumnPickerWpProps.ts
Use the following interface:
export interface IPropertyFieldColumnPickerWpProps { description: string; isDarkTheme: boolean; environmentMessage: string; userDisplayName: string; list: string; column: string; multiColumn: string[];}
These properties receive the values stored in the Web Part class.
The values are passed to the React component during the Web Part render() method:
list: this.properties.list,column: this.properties.column,multiColumn: this.properties.multiColumn || []
This is the connection between the Property Pane and the React component.
The complete flow is:
Property Pane ↓this.properties ↓React.createElement ↓React component props ↓Rendered Web Part
React Component
Create or update:
src/webparts/propertyFieldColumnPickerWp/components/PropertyFieldColumnPickerWp.tsx
Use the following code:
import * as React from 'react';import { IPropertyFieldColumnPickerWpProps} from './IPropertyFieldColumnPickerWpProps';const PropertyFieldColumnPickerWp: React.FC<IPropertyFieldColumnPickerWpProps> = ({ description, list, column, multiColumn }) => { return ( <section> <h2> PropertyFieldColumnPicker </h2> <p> {description} </p> <h3> Selected list or library </h3> <p> {list || 'No list selected'} </p> <h3> Selected column </h3> <p> {column || 'No column selected'} </p> <h3> Multiple selected columns </h3> {multiColumn && multiColumn.length > 0 ? ( <ul> {multiColumn.map( ( columnName: string, index: number ) => ( <li key={`${columnName}-${index}`} > {columnName} </li> ) )} </ul> ) : ( <p> No columns selected </p> )} </section> ); };export default PropertyFieldColumnPickerWp;
The component displays:
- The configured description
- The SharePoint list ID
- The selected single column
- All selected multiple columns
The map() method transforms the selected column array into an HTML list.
The context TypeScript Error
During compilation, the following error may occur:
Type 'WebPartContext' is not assignable to type'BaseComponentContext'.
The complete message can also mention incompatible versions of:
@microsoft/sp-module-interfaces
and:
@microsoft/sp-http-base
This usually means the SPFx solution has two dependency trees containing incompatible versions of an internal Microsoft package.
One dependency expects one version of BaseComponentContext, while the current SPFx Web Part provides another version of WebPartContext.
Although both contexts represent the SPFx component context, TypeScript treats them as incompatible because they originate from different package installations.
The temporary correction used in this project is:
context: this.context as any
Instead of:
context: this.context
The resulting configuration is:
PropertyFieldColumnPicker( 'column', { context: this.context as any })
This cast only affects TypeScript’s compile-time validation. At runtime, the actual WebPartContext instance is still passed to the PnP control.
The official control expects a BaseComponentContext through its context property. (Microsoft 365 Community)
Cleaning the SPFx Solution
When dependency conflicts appear, clean the project before testing again:
heft clean
Then start the local SPFx development server:
heft start
For a more complete dependency reset, use:
Remove-Item ` -Path ".\node_modules" ` -Recurse ` -Force
Remove the lock file:
Remove-Item ` -Path ".\package-lock.json" ` -Force
Restore the dependencies:
npm install
Clean the project:
heft clean
Start the project:
heft start
The as any cast may still be necessary when the currently installed version of the PnP package references a different internal SPFx dependency tree.
Errors Corrected in the Original Implementation
Incorrect list property
The original code used:
listId: this.properties.singleListFiltered
However, singleListFiltered did not exist in the Web Part properties interface.
The correct property is:
listId: this.properties.list
The name used in this.properties must exactly match a property declared in the Web Part interface.
Incorrect multiple-column type
The original interface declared:
multiColumn: string;
For multiple selections, it should be:
multiColumn: string[];
This allows the Web Part to store all selected columns instead of only one value.
Invalid null validation callback
The original configuration used:
onGetErrorMessage: null
With strict TypeScript checking, null is not compatible with an optional validation function.
Because validation is not required in this example, the property should simply be removed.
Do not use:
onGetErrorMessage: null
Omit it entirely:
deferredValidationTime: 0
The onGetErrorMessage property is optional and is used only when custom validation is required. (Microsoft 365 Community)
Duplicate property names
Two controls in the original code used:
PropertyFieldColumnPicker( 'multiColumn', ...)
This causes both controls to update the same Web Part property.
For this demonstration, only one multiple-column picker is required.
When two independent controls are needed, define separate properties:
multiColumnChoiceGroup: string[];multiColumnDropdown: string[];
Then use separate control names:
PropertyFieldColumnPicker( 'multiColumnChoiceGroup', ...)
and:
PropertyFieldColumnPicker( 'multiColumnDropdown', ...)
Each control should also have a unique key.
Missing comma
The original code contained:
multiSelect: truerenderFieldAs: IPropertyFieldRenderOption[ 'Multiselect Dropdown' ]
A comma was missing after true.
The correct syntax is:
multiSelect: true,renderFieldAs: IPropertyFieldRenderOption[ 'Multiselect Dropdown' ]
Missing enum imports
The original example referenced:
IColumnReturnProperty
and:
IPropertyFieldRenderOption
without importing them.
The simplified implementation avoids these properties and uses the default return and rendering behavior.
This keeps the example focused on the primary purpose of the control: selecting one or more SharePoint columns.
Important Control Properties
label
Defines the label displayed above the control:
label: 'Select a column'
listId
Defines the SharePoint list or library from which columns are retrieved:
listId: this.properties.list
The value must contain the list GUID.
context
Provides the current SPFx component context:
context: this.context as any
The context is required by the control. (Microsoft 365 Community)
selectedColumn
Defines the current selected column or columns:
selectedColumn: this.properties.column
or:
selectedColumn: this.properties.multiColumn
multiSelect
Controls whether one or multiple columns can be selected:
multiSelect: false
or:
multiSelect: true
orderBy
Controls how the available columns are sorted:
orderBy: PropertyFieldColumnPickerOrderBy.Title
displayHiddenColumns
Controls whether hidden SharePoint fields are shown:
displayHiddenColumns: false
properties
Passes the complete Web Part properties object to the PnP control:
properties: this.properties
The control uses this object when updating the configured property value.
onPropertyChange
Connects the custom PnP control to the standard SPFx property change lifecycle:
onPropertyChange: this.onPropertyPaneFieldChanged.bind(this)
When the selection changes, the selected value is written into the corresponding Web Part property.
key
Defines a unique identity for the Property Pane control:
key: 'columnPickerFieldId'
Each control should use a unique key:
key: 'multiColumnPickerFieldId'
Recommended Combination with PropertyFieldListPicker
In a production Web Part, users should not normally type a list GUID manually.
The recommended approach is to combine:
PropertyFieldListPicker
with:
PropertyFieldColumnPicker
The list picker first allows the user to select a SharePoint list.
Its selected list ID is stored in:
this.properties.list
The column picker then uses that value:
listId: this.properties.list
The official documentation specifically recommends using the column picker together with PropertyFieldListPicker, configured to select a single list. (Microsoft 365 Community)
The resulting configuration flow is:
Select a SharePoint list ↓Store its list ID ↓Load the list columns ↓Select one or more columns ↓Store the selected column values
Testing the Web Part
Start the SPFx development environment:
heft start
Open the SharePoint-hosted Workbench.
Add the PropertyFieldColumnPickerWp Web Part.
Open the Web Part Property Pane.
Enter a valid SharePoint list or library GUID.
The column controls should become enabled.
Select one column in the first picker.
Select multiple columns in the second picker.
The selected values should immediately appear in the React component.
Conclusion
The PropertyFieldColumnPicker provides a better configuration experience than requiring users to manually enter SharePoint field names.
It can retrieve available fields from a selected SharePoint list, support single or multiple selections, hide internal fields, sort available options, and store the selection directly in the Web Part properties.
The most important implementation details are:
list: string;column: string;multiColumn: string[];
The column picker must receive the selected list ID:
listId: this.properties.list
Multiple selections must use:
multiSelect: true
The Web Part properties must be connected through:
onPropertyChange: this.onPropertyPaneFieldChanged.bind(this)
In solutions affected by duplicated SPFx dependency types, the context can temporarily be passed as:
context: this.context as any
With these corrections, the Web Part can compile successfully and provide both single-column and multiple-column selection in the SPFx Property Pane.
Official Documentation
O próximo refinamento natural desse artigo é substituir o campo manual de GUID pelo PropertyFieldListPicker, deixando a seleção da lista e das colunas totalmente integrada.
