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: true
renderFieldAs:
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.

Edvaldo Guimrães Filho Avatar

Published by