SPFx + PnP React Controls: Working with FieldCollectionData
When building solutions with the SharePoint Framework, one common challenge is handling structured collections of data inside a form or component. Many business scenarios require users to add multiple rows of information dynamically, such as links, contacts, product lists, configurations, or metadata sets.
That is exactly where the PnP SPFx React Controls FieldCollectionData control becomes important.
FieldCollectionData is a reusable editor that allows users to create, edit, paginate, filter, and validate collections of objects directly in the UI.
Official documentation:
FieldCollectionData Documentation
Why is FieldCollectionData important?
In traditional SPFx development, if you need a collection of structured rows, you usually have to build:
- A modal panel
- Add/Edit forms
- Validation logic
- Filtering logic
- State management
- Pagination
- Serialization
That means a lot of repetitive work.
FieldCollectionData solves this by giving you:
- Dynamic field generation
- Strong typed field definitions
- Built-in editing panel
- Built-in paging
- Filtering support
- Validation
- Easy integration with JSON storage
This makes it extremely useful for:
- Configurable web parts
- Property pane collections
- Dynamic metadata editors
- Multi-item business forms
Understanding your example
Your component imports:
import { FieldCollectionData, CustomCollectionFieldType } from '@pnp/spfx-controls-react/lib/FieldCollectionData';
This gives access to:
| Object | Purpose |
|---|---|
| FieldCollectionData | Main collection editor |
| CustomCollectionFieldType | Defines field types |
Full Example
FC.tsx
import * as React from 'react';import { FieldCollectionData, CustomCollectionFieldType } from '@pnp/spfx-controls-react/lib/FieldCollectionData';const FC: React.FC = () => { return ( <FieldCollectionData key={"FieldCollectionData"} label={"Fields Collection"} manageBtnLabel={"Manage"} panelHeader={"Manage values"} onChanged={(value) => { console.log("Updated collection:", value); }} executeFiltering={(searchFilter: string, item: any) => { return item["Field2"] === +searchFilter; }} itemsPerPage={3} fields={[ { id: "Field1", title: "String field", type: CustomCollectionFieldType.string, required: true }, { id: "Field2", title: "Number field", type: CustomCollectionFieldType.number }, { id: "Field3", title: "URL field", type: CustomCollectionFieldType.url }, { id: "Field4", title: "Boolean field", type: CustomCollectionFieldType.boolean } ]} value={[ { Field1: "String value", Field2: "123", Field3: "https://pnp.github.io/", Field4: true } ]} /> );};export default FC;
Breaking down the properties
label
label={"Fields Collection"}
Defines the visible title.
Example:
Fields Collection
manageBtnLabel
manageBtnLabel={"Manage"}
Defines the button label to open the management panel.
panelHeader
panelHeader={"Manage values"}
Sets the panel title.
onChanged
onChanged={(value) => { console.log(value);}}
This event returns the updated collection.
Example output:
[ { "Field1": "Test", "Field2": 50, "Field3": "https://site.com", "Field4": true }]
This is critical because it allows:
- Saving to SharePoint lists
- Saving to web part properties
- Sending to APIs
executeFiltering
executeFiltering={(searchFilter, item) => { return item["Field2"] === +searchFilter;}}
Allows custom filtering logic.
Here:
- Converts input to number
- Matches against Field2
Useful for advanced search.
itemsPerPage
itemsPerPage={3}
Controls pagination.
Without this, large collections become difficult to manage.
Field definitions
The fields array defines the schema.
String field
{ id: "Field1", title: "String field", type: CustomCollectionFieldType.string, required: true}
Simple text.
Number field
{ id: "Field2", title: "Number field", type: CustomCollectionFieldType.number}
Numeric input.
URL field
{ id: "Field3", title: "URL field", type: CustomCollectionFieldType.url}
Validates URLs.
Boolean field
{ id: "Field4", title: "Boolean field", type: CustomCollectionFieldType.boolean}
Creates a toggle/checkbox.
Initial data
value={[ { Field1: "String value", Field2: "123", Field3: "https://pnp.github.io/", Field4: true }]}
This preloads data into the collection.
Very useful for:
- Edit forms
- Existing configurations
- Stored JSON
Real-world SPFx scenarios
Navigation links
[ { "Title": "Home", "Url": "/sites/home" }]
Team members
[ { "Name": "John", "Role": "Developer" }]
Product catalog
[ { "Product": "Laptop", "Price": 2500 }]
Why use this in SPFx?
The FieldCollectionData control saves enormous development time.
Without it:
- More code
- More bugs
- More validation logic
With it:
- Faster UI building
- Better user experience
- Cleaner code
- Standardized editing experience
For enterprise SharePoint solutions, this control is one of the most practical in the entire Microsoft 365 ecosystem.
Progress Roadmap
| WP | Control | Status |
|---|---|---|
| WP01 | AccessibleAccordion | ✅ |
| WP02 | Accordion | ✅ |
| WP03 | AdaptiveCardHost | ✅ |
| WP04 | AnimatedDialog | ✅ |
| WP05 | Carousel | ✅ |
| WP06 | ChartControl | ✅ |
| WP07 | Dashboard | ✅ |
| WP08 | DragDropFiles | ✅ |
| WP09 | EnhancedThemeProvider | ✅ |
| WP10 | FieldCollectionData | ✅ |
