🚀 Building a Dynamic SPFx Form Web Part in React – Real-World Use Case with Code Walkthrough
🎯 Introduction
In one of my recent SharePoint Framework (SPFx) projects, I needed to build a dynamic form web part that:
- Allowed the user to search by ID
- Fetched values from a SharePoint list
- Auto-filled dropdowns and number fields
- Let users edit and save the data back to the list
This blog post walks through the entire process — not just the code, but the why behind each step.
💡 The Use Case
Imagine you have a SharePoint list called SubmittedForms where each item stores:
- A project name, department, and client
- Three 4-digit number fields (
Field1,Field2,Field3)
All fields are stored as plain text, not lookup. Your form should:
- ✅ Allow searching by ID
- ✅ Auto-fill the dropdowns and number fields
- ✅ Allow editing and saving
- ✅ Validate number fields against other reference lists
⚙️ Environment Setup
- SPFx Version: 1.18.2
- React Version: 17.0.2
- PnPjs Version: 3.17.0
- Node.js Version: 16.x (LTS)
- Platform: SharePoint Online
📋 Required SharePoint Lists
SubmittedForms– main list with all form fieldsProjects,Departments,Clients– dropdown source listsValidNumbers1,ValidNumbers2,ValidNumbers3– for validating 4-digit numbers
🧱 Why We Split into Components
Instead of cramming everything into one file, we broke the form into reusable components:
| Component | Purpose |
|---|---|
| FormWebPart.tsx | Main form logic and state |
| DropdownField.tsx | Reusable dropdown control |
| NumericTextField.tsx | Reusable number-only field with validation |
| SPService.ts | All PnPjs operations like fetching, saving, updating |
🧠 Why React Hooks?
Hooks like useState, useEffect, and useMemo make the form logic clean and predictable.
const [dropdowns, setDropdowns] = useState({});
const [textFields, setTextFields] = useState({});
🧩 Passing Props Between Components
To make DropdownField reusable:
<DropdownField
label="Select Project"
options={dropdownOptions['Projects']}
selectedKey={dropdowns['Projects']}
onChange={(option) => handleDropdownChange('Projects', option)}
/>
The child component receives the selected key and options from the parent and notifies the parent when a change happens.
💬 Validating 4-digit Numbers
Each number field must be exactly 4 digits and validated against other SharePoint lists with IsActive = true:
if (!/^\d{4}$/.test(value)) {
newErrors[key] = 'Enter a 4-digit number';
} else {
const isValid = await spService.validateNumberAcrossLists(validationLists, value);
if (!isValid) {
newErrors[key] = 'Invalid or inactive number';
}
}
🔁 Fetching and Auto-Filling Data by ID
When a user types an ID and clicks Search, we fetch the item and bind text fields:
const item = await spService.getItemById(listName, searchId);
setDropdowns({
Projects: item.Projects,
Departments: item.Departments,
Clients: item.Clients
});
setTextFields({
Field1: item.Field1,
Field2: item.Field2,
Field3: item.Field3
});
💾 Save vs Update Logic
We conditionally create or update the SharePoint item based on ID presence:
if (itemId) {
await spService.updateItem(listName, itemId.toString(), payload);
alert('✅ Item updated successfully!');
} else {
await spService.saveFormData(listName, payload);
alert('✅ New item saved successfully!');
}
📦 Folder Structure
src/
└── webparts/
└── formWebPart/
├── components/
│ ├── FormWebPart.tsx
│ ├── DropdownField.tsx
│ └── NumericTextField.tsx
├── services/
│ └── SPService.ts
└── FormWebPartWebPart.tsx
📷 Live Demo (User Flow)
- 🔎 Type ID:
123and click Search - ✅ Dropdowns auto-filled:
Project A,Department B,Client X - 🖊️ Edit
Field2from1234to3456 - 💾 Click Save → Success alert!
📌 Key Takeaways
- Keep SharePoint fields simple using Single Line of Text when Lookup isn't necessary
- Use reusable React components to reduce repetition
- React hooks like
useStateanduseMemosimplify logic - PnPjs makes SharePoint integration clean and efficient
- Always validate input before save/update
💭 Final Thoughts
This project reminded me that SPFx can be incredibly flexible when you combine modern React with clean service layers. The reusable architecture will also help you scale the solution across different forms.
Would you like a GitHub link to the full source code or video demo walkthrough?
Connect with me on LinkedIn and let me know.
✅ Stay tuned for Part 2: Adding toast notifications, language localization, and production deployment tips.
Comments
Post a Comment