Using the PnP PropertyFieldCollectionData Control in an SPFx Web Part

The PropertyFieldCollectionData control allows users to create and manage a collection of structured records directly from the SharePoint Framework property pane.

Instead of adding only one text field or one dropdown, this control opens a panel where users can create multiple rows containing different field types.

In this example, each row represents a person and contains:

  • First name
  • Last name
  • Age
  • Favorite city
  • Signed status

The collection is stored in the web part properties and can then be passed to the React component for rendering.

The control supports several field types, including strings, numbers, Boolean values, dropdowns, URLs, colors, icons, and custom fields.

Official documentation

PnP PropertyFieldCollectionData documentation:


Install the PnP Property Controls package

Open PowerShell in the root folder of the existing SPFx solution.

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

After installing the dependency, restore the complete solution packages.

npm install

Import the control

Open the main web part file:

PropertyFieldCollectionDataWpWebPart.ts

Add the following import:

import {
PropertyFieldCollectionData,
CustomCollectionFieldType
} from '@pnp/spfx-property-controls/lib/PropertyFieldCollectionData';

This is the official import path documented by the PnP project.


Define the web part properties

The collection must be stored in the web part properties as an array.

export interface IPropertyFieldCollectionDataWpWebPartProps {
description: string;
collectionData: any[];
}

The collectionData property will contain every row created through the property pane.

A saved collection can have a structure similar to this:

[
{
"Title": "John",
"Lastname": "Smith",
"Age": 42,
"City": "helsinki",
"Sign": true
},
{
"Title": "Anna",
"Lastname": "Taylor",
"Age": 35,
"City": "montreal",
"Sign": false
}
]

The shape of each object is determined by the fields configured in the control.


Configure the property pane control

Add PropertyFieldCollectionData to the groupFields array.

PropertyFieldCollectionData('collectionData', {
key: 'collectionData',
label: 'Collection data',
panelHeader: 'Collection data panel header',
manageBtnLabel: 'Manage collection data',
value: this.properties.collectionData,
fields: [
{
id: 'Title',
title: 'Firstname',
type: CustomCollectionFieldType.string,
required: true
},
{
id: 'Lastname',
title: 'Lastname',
type: CustomCollectionFieldType.string
},
{
id: 'Age',
title: 'Age',
type: CustomCollectionFieldType.number,
required: true
},
{
id: 'City',
title: 'Favorite city',
type: CustomCollectionFieldType.dropdown,
options: [
{
key: 'antwerp',
text: 'Antwerp'
},
{
key: 'helsinki',
text: 'Helsinki'
},
{
key: 'montreal',
text: 'Montreal'
}
],
required: true
},
{
id: 'Sign',
title: 'Signed',
type: CustomCollectionFieldType.boolean
}
],
disabled: false
})

The first argument, 'collectionData', connects the control to:

this.properties.collectionData

The value property provides the current collection to the control:

value: this.properties.collectionData

When the user saves the panel, SPFx updates the corresponding web part property.


Understanding the control properties

key

key: 'collectionData'

Provides a unique identity for the property pane control.

label

label: 'Collection data'

Displays the control label in the property pane.

panelHeader

panelHeader: 'Collection data panel header'

Defines the title displayed at the top of the collection management panel.

manageBtnLabel

manageBtnLabel: 'Manage collection data'

Defines the text of the button that opens the panel.

value

value: this.properties.collectionData

Connects the control to the data stored in the web part properties.

fields

fields: []

Defines the columns available in each collection row.

disabled

disabled: false

Determines whether users can interact with the control.

The PnP control also supports optional settings such as sorting, custom panel styles, preventing item creation, and preventing item deletion.


Understanding the collection fields

Each object inside the fields array creates one column.

String field

{
id: 'Title',
title: 'Firstname',
type: CustomCollectionFieldType.string,
required: true
}

This field renders a text input.

The id becomes the property name in the saved object:

{
"Title": "John"
}

The title is the label shown to the user.


Number field

{
id: 'Age',
title: 'Age',
type: CustomCollectionFieldType.number,
required: true
}

This field accepts numeric values.

The saved value is stored as a number:

{
"Age": 42
}

Dropdown field

{
id: 'City',
title: 'Favorite city',
type: CustomCollectionFieldType.dropdown,
options: [
{
key: 'antwerp',
text: 'Antwerp'
},
{
key: 'helsinki',
text: 'Helsinki'
},
{
key: 'montreal',
text: 'Montreal'
}
],
required: true
}

Dropdown fields require an options array.

The key is stored in the web part properties:

{
"City": "helsinki"
}

The text is displayed to the user:

Helsinki

Boolean field

{
id: 'Sign',
title: 'Signed',
type: CustomCollectionFieldType.boolean
}

This field renders a checkbox.

The saved value is either:

{
"Sign": true
}

or:

{
"Sign": false
}

Initialize the collection

It is useful to ensure that the property contains an array before rendering the property pane.

Update the onInit method:

protected onInit(): Promise<void> {
if (!this.properties.collectionData) {
this.properties.collectionData = [];
}
return this._getEnvironmentMessage().then(message => {
this._environmentMessage = message;
});
}

This prevents collectionData from being undefined the first time the web part is added to a page.


Pass the collection to the React component

Inside the web part render method, pass the property to the React component:

public render(): void {
const element: React.ReactElement<IPropertyFieldCollectionDataWpProps> =
React.createElement(
PropertyFieldCollectionDataWp,
{
description: this.properties.description,
collectionData: this.properties.collectionData || []
}
);
ReactDom.render(element, this.domElement);
}

The fallback array ensures the component always receives a valid collection.


React component properties

Create or update:

components/IPropertyFieldCollectionDataWpProps.ts
export interface ICollectionDataItem {
Title: string;
Lastname?: string;
Age: number;
City: string;
Sign?: boolean;
}
export interface IPropertyFieldCollectionDataWpProps {
description: string;
collectionData: ICollectionDataItem[];
}

Using an interface instead of any[] inside the React component provides better TypeScript validation.

The web part property can remain any[], matching the basic example from the official documentation, while the component uses a stronger type for rendering.


Render the collection in React

Open:

components/PropertyFieldCollectionDataWp.tsx

Use the following component:

import * as React from 'react';
import {
ICollectionDataItem,
IPropertyFieldCollectionDataWpProps
} from './IPropertyFieldCollectionDataWpProps';
const PropertyFieldCollectionDataWp:
React.FC<IPropertyFieldCollectionDataWpProps> = ({
description,
collectionData
}) => {
return (
<section>
<h2>PropertyFieldCollectionData</h2>
<p>{description}</p>
{collectionData.length === 0 ? (
<p>
Open the web part property pane and select
<strong> Manage collection data</strong>.
</p>
) : (
<table>
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
<th>Favorite city</th>
<th>Signed</th>
</tr>
</thead>
<tbody>
{collectionData.map(
(item: ICollectionDataItem, index: number) => (
<tr key={`${item.Title}-${index}`}>
<td>{item.Title}</td>
<td>{item.Lastname || '-'}</td>
<td>{item.Age}</td>
<td>{item.City}</td>
<td>{item.Sign ? 'Yes' : 'No'}</td>
</tr>
)
)}
</tbody>
</table>
)}
</section>
);
};
export default PropertyFieldCollectionDataWp;

The component verifies whether records exist:

collectionData.length === 0

When the collection is empty, it displays instructions for opening the property pane.

When records exist, the component uses map to render one table row for each collection item.


Complete web part property pane configuration

The relevant section of the web part is:

protected getPropertyPaneConfiguration():
IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyFieldCollectionData('collectionData', {
key: 'collectionData',
label: 'Collection data',
panelHeader: 'Collection data panel header',
manageBtnLabel: 'Manage collection data',
value: this.properties.collectionData,
fields: [
{
id: 'Title',
title: 'Firstname',
type: CustomCollectionFieldType.string,
required: true
},
{
id: 'Lastname',
title: 'Lastname',
type: CustomCollectionFieldType.string
},
{
id: 'Age',
title: 'Age',
type: CustomCollectionFieldType.number,
required: true
},
{
id: 'City',
title: 'Favorite city',
type: CustomCollectionFieldType.dropdown,
options: [
{
key: 'antwerp',
text: 'Antwerp'
},
{
key: 'helsinki',
text: 'Helsinki'
},
{
key: 'montreal',
text: 'Montreal'
}
],
required: true
},
{
id: 'Sign',
title: 'Signed',
type: CustomCollectionFieldType.boolean
}
],
disabled: false
})
]
}
]
}
]
};
}

Run the solution

Start the local development environment with Heft:

heft start

Add the web part to the SharePoint workbench or to a modern SharePoint page.

Then:

  1. Edit the web part.
  2. Open the property pane.
  3. Select Manage collection data.
  4. Add one or more people.
  5. Complete the required fields.
  6. Save the collection.
  7. Confirm that the records appear in the React component.

Additional capabilities

The control can also enable manual sorting:

enableSorting: true

Prevent users from creating new records:

disableItemCreation: true

Prevent users from deleting existing records:

disableItemDeletion: true

Add a description to the panel:

panelDescription:
'Create and manage the people displayed by this web part.'

Example:

PropertyFieldCollectionData('collectionData', {
key: 'collectionData',
label: 'Collection data',
panelHeader: 'Manage people',
panelDescription:
'Create and manage the people displayed by this web part.',
manageBtnLabel: 'Manage collection data',
value: this.properties.collectionData,
enableSorting: true,
fields: [
// Collection fields
],
disabled: false
})

The official control also supports custom validation and completely custom field rendering when the standard field types are not sufficient.


Conclusion

PropertyFieldCollectionData is one of the most powerful PnP SPFx property pane controls because it allows content editors to manage structured and repeatable information without changing the source code.

The control manages the editing experience, validation, row creation, deletion, and optional sorting. The web part only needs to define the fields, store the resulting array, and pass that array to the React component.

This approach is useful for collections such as:

  • Offices and locations
  • Contact information
  • Frequently asked questions
  • Navigation links
  • Products or services
  • Team members
  • Configuration rules
  • Dashboard items

Official documentation:

Edvaldo Guimrães Filho Avatar

Published by