Excel-Powered CRUD in SharePoint List using PnP JS and XLSX

Overview  

Utilizing Excel as an information source, PnP JS for SharePoint operations, and the XLSX library for parsing Exceed expectations records, I will walk you how to perform out CRUD (Create, Read, Update, Delete) method in a SharePoint list.

Excel Powered CRUD in SharePoint List using PnP JS and XLSX

We’ll cover two ways to handle the data: 

  • Static Approach – Hardcoded fields for quick implementation. 
  • Dynamic Approach – Automatically adapts to any list structure by reading Excel headers. 

Whether you're a beginner or a seasoned SharePoint developer, this guide will help you integrate Excel uploads with your SharePoint list seamlessly! 

Prerequisites 

Sometime recently we start, guarantee you’ve got the desired bundles installed. Execute the following command in your terminal: 

npm install @pnp/sp @pnp/spfx @pnp/odata xlsx --save

Set Up Your SharePoint Framework (SPFx) Project 

Configure the WebPart.ts File

import { SPFI, spfi } from "@pnp/sp";
import { SPFx } from "@pnp/sp";  
 
export let sp: SPFI;
 
protected async onInit(): Promise<void> {
 sp = spfi().using(SPFx(this.context));
 try {
   const message = await this._getEnvironmentMessage();
   this._environmentMessage = message;
   return super.onInit();
 } catch (error) {
   console.error("Error fetching environment message:", error);
 }
}

Create a Simple State Interface 

If you don't already have a state file, create one: 

export interface IExcelThroughUploadDataToSharePointState {
  fileName: string | null;
}

Handling Excel Upload in .tsx File 

Import Required Modules

import * as XLSX from 'xlsx';
import { sp } from '../ExcelThroughUploadDataToSharePointWebPart';
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";  

Add Constructor

constructor(props: any) {
  super(props);
  this.state = {
    fileName: null
  };
}  

Handling File Upload and Data Processing 

Upload & Process Excel File

private handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
  this.setState({ fileName: null });
  const file = event.target.files?.[0];
  if (!file) return;
  this.setState({ fileName: file.name });
 
  const reader = new FileReader();
  reader.onload = async (e: ProgressEvent<FileReader>) => {
    const data = e.target?.result;
    const workbook = XLSX.read(data, { type: 'binary' });
    const worksheet = workbook.Sheets[workbook.SheetNames[0]];
    const jsonData = XLSX.utils.sheet_to_json(worksheet) as any[];
    /*
      We are using as any[] with XLSX.utils.sheet_to_json(worksheet) to quickly
      convert the Excel sheet into JSON format without TypeScript errors or
      warnings. This is a fast and flexible mthod, easpecially useful during
      early development stages when typing isn't necessary. Alternatively,
      for better type safety and IntelliSense support, you can define
      a TypeScript interface like this:
      interfacee ITask {
        Title: string;
        Description: string;
        Status: string;
        DueDate: date;
      }
   
      Then use the generic version of sheet_to_json like this:
      const jsonData = XLSX.utils.sheet_to_json<ITask>(worksheet);
    */
 
    /* To fetch existing items from the SharePoint list named "ProjectTasks",
    we use the following PnPjs method: */
    const existingItems = await sp.web.lists.getByTitle("ProjectTasks").items
    .select("Id", "Title", "Description", "Status")();
    /*  
      In this code:
        - () is important - in the newer SPFI-based version of PnPjs
        (@pnp/sp version 2.x and above), instead of calling .get() at the
        end of the chain, you invoke the entire chain as a function using ().
      This returns the array of results directly.
    */

    /*  
      Create a map for easy lookup of Excel data.
      This helps in checking whether a specific item (based on Title)
      already exists.
        - If the item exists, it can be updated.
        - If it doesn't exist, it can be added.
        - If an existing item is no longer present in the Excel data,
        it can be removed.
    */
    const excelMap = new Map<string, any>();
    jsonData.forEach(item => {
      if (item.Title) excelMap.set(item.Title.trim(), item);
    });
 
    const spMap = new Map<string, any>();
    existingItems.forEach(item => {
      if (item.Title) spMap.set(item.Title.trim(), item);
    });
 
    /*  
      Perform update or create a new entry:
        - Check in the event that the thing from Excel exists within the SharePoint list.
      This ensures the Excel information, and the SharePoint list remains in at this point.
    */
    for (const [title, excelItem] of excelMap) {
      /* update items */
      if (spMap.has(title)) {
        const spItem = spMap.get(title);
        await await sp.web.lists.getByTitle('ProjectTasks').items
        .getById(spItem.Id).update({
             Title: excelItem.Title,
             Description: excelItem.Description,
             Status: excelItem.Status,
             DueDate: this.convertExcelSerialToDate(excelItem.DueDate).toISOString()
           });
        spMap.delete(title);
      } else {
        await sp.web.lists.getByTitle('ProjectTasks').items.add({
          Title: excelItem.Title,
          Description: excelItem.Description,
          Status: excelItem.Status,
          DueDate: this.convertExcelSerialToDate(excelItem.DueDate).toISOString()
        });
      }
    }
 
    /*
     Delete remaining SharePoint items not found in Excel  
    */
    for (const [title, spItem] of spMap) {
      await sp.web.lists.getByTitle("ProjectTasks").items
      .getById(spItem.Id).recycle(); // Use .delete() if permanent removal is needed
    }

    alert('Excel data synced with SharePoint list successfully!');
  };
  reader.readAsBinaryString(file);
}

Dynamic Approach 

  /*  
    Dynamic field mapping:
      - This approach allows you to add or remove columns in the Excel file,
      and those changes will automatically reflect in the SharePoint List items
      without needing to change the code.
   */

  /* #### How it works: */
  const itemToAdd: any = {};
  Object.keys(excelItem).forEach(key => {
    itemToAdd[key] = excelItem[key];
  });

  /* #### add item  */
  await sp.web.lists.getByTitle("ProjectTasks").items.add(itemToAdd);

  /* #### update item */
  await sp.web.lists.getByTitle("ProjectTasks").items.getById(spItem.Id).update(itemToAdd);  

/*
  Explanation:
    - `Object.keys(excelItem)` retrieves all column names (as key) from the Excel row.
    - The loop dynamically builds a SharePoint item using those keys and values.
    - This ensures that any number of columns (2 or more) in Exceel will be correctly handled.
    - You do not need to hard-code field names - updates to Excel structure will still work.
*/

Converting Excel Date to SharePoint-Compatible Format 

public convertExcelSerialToDate = (serial: number): Date => {
  return new Date((serial - 25569) * 86400 * 1000);
};

Explanation: 

Excel stores dates as serial numbers. This method converts it into a valid JavaScript Date object. 

/*  
  Convert Excel date to Unix Epoch (in milliseconds):
    - Excel stores dates as serial numbers, starting from Jan 1, 1970.
    - To convert Excel serial date to Unix epoch time (starts from Jan 1, 1970):
  Substract 25569 from the Excel serial date
    - because 25569 is the number of days between Jan 1, 1900 and Jan 1, 1970.
  Convert the result to seconds:
    - (serial - 25569) * 86400
    - 86400 is the number of seconds in a day.
  Convert to milliseconds:
    - seconds * 1000
    - Final result will be a JavaScript-compatible timestamp.
*/

Render Upload UI 

public render(): React.ReactElement<IExcelThroughUploadDataToSharePointProps> {
  return (
    <div>
      <input type='file' accept=".xlsx, .xls" onChange={this.handleFileUpload} />
      {this.state.fileName && <p>Uploading: {this.state.fileName}</p>}
    </div>
  );
}

Tips for Using Excel Effectively 

  • Ensure your Excel column headers match the internal field names in SharePoint. 
  • If you're using dates, convert them into text format in Excel before uploading. 
  • Dynamic field handling allows you to change list columns without editing the code. 

What You’ve Achieved 

By the end of this tutorial, you now know how to: 

  • Upload an Excel file in SPFx. 
  • Parse the file using XLSX. 
  • Perform Create, Update, and Delete operations powerfully on a SharePoint list. 
  • Handle dates and dynamic columns gracefully. 

Final Thoughts 

  • Using Excel as a front-facing CRUD interface makes SharePoint even more accessible for end-users. With PnP JS and XLSX to make the syncing handle makes it dynamic and future-proof!  
  • Let me know in the comments if you'd like a downloadable sample, a reusable component, or a ready-to-go SPFx solution package.

Send Emails in SPFx Using SP Utility – The Easy Way!

Overview : 

Sending emails is one of the most common functionalities in enterprise-level SharePoint solutions. From notifying users to triggering alerts and approvals, email communication is crucial. 

Luckily, with SharePoint Framework (SPFx) and the PnP JS library, you can send rich HTML emails directly using sp.utility.sendEmailwithout needing Power Automate, a backend API, or Third-party tools. 

In this blog, I will guide you step-by-step on how to send formatted emails in SPFx using the powerful yet simple sp.utility.sendEmail method. 

Send Emails in SPFx using SP Utility PnP JS library

Prerequisites : 

Before we dive into the code, make sure you have the following ready: 

  • SPFx solution created using Yeoman generator. 
  • PnP JS (@pnp/sp) library installed in your solution. 
  • Appropriate permission granted to the current user for sending emails.  

Install PnP JS : 

If you haven’t already, run the following command in your solution directly: 

npm install @pnp/sp @pnp/logging @pnp/common @pnp/odata --save

Import Required Modules : 

At the top of your component or service file. 

import { sp } from "@pnp/sp";
import "@pnp/sp/utility";
import { IEmailProperties } from "@pnp/sp/utility/types";

Implementation : 

Here’s the reusable method that allows you to send emails using sp.utility.sendEmail from your SPFx web part or extension: 

public async sendEmail(to: string[], cc: string[], subject: string, body: string) {
 const emailProps: IEmailProperties = {
   To: to,
   CC: cc,
   Subject: subject,
   Body: body,
   AdditionalHeaders: {
     "content-type": "text/html"
   }
 };
 
 try {

    console.log("Sending email with the following details:", emailProps);

    await sp.utility.sendEmail(emailProps);

    console.log("Email delivered successfully.");

  } catch (error) {

    console.error("Failed to send email:", error);

  }
}

Explanation : 

  • To: Array of recipient email addresses. 
  • CC: Array of CC recipients. 
  • Subject: Email subject line. 
  • Body: Email body, Supports both plain text and HTML. 
  • AdditionalHeaders: Optional. If your body is HTML-formatted, set "content-type": "text/html" to ensure proper rendering. 

Example Usage : 

You can trigger the email function on a button click or event handler like this: 

this.sendEmail(
  ["user@example.com"],
  ["manager@example.com"],
  "SPFx Email Notification",
  "<p>Hello <strong>User</strong>,<br />This is a test email from SPFx.</p>"
 );

Permission Consideration : 

You do not need Microsoft Graph API to use this method. The SharePoint REST API is used behind the scenes by sp.utility.sendEmail. Make sure the API has permission to send emails. In your package-solution.json, add the following under webApiPermissionRequests if needed: 

"webApiPermissionRequests": [
 {
   "resource": "Microsoft Graph",
   "scope": "Mail.Send"
 }
]

Note: If you're using only SharePoint APIs, ensure that your SPFx solution has the necessary SharePoint permissions and is approved in the tenant app catalog. 

Benefits of Using sp.utility.sendEmail : 

  • No backend or Power Automate dependency. 
  • Lightweight and easy to integrate in any SPFx component. 
  • Supports HTML and plain text email formats. 
  • Encourages reusability across components or solutions. 
  • No external configuration if user has default SharePoint email rights. 
  • Ideal for alerts, notifications, and internal workflows. 

Pro Tips : 

  • Avoid sending emails in loops—consider batching where possible. 
  • Test in development/staging environments before live rollout. 
  • Sanitize user input in the email body to avoid script injection. 
  • Use environment-based logic to control when and where emails are sent. 
  • Format HTML correctly for compatibility across different mail clients. 

Conclusion : 

  • With just a few lines of code, you can send dynamic, formatted HTML emails directly from your SPFx web part using sp.utility.sendEmail method. It’s reliable, efficient, and works perfectly in SPFx environments for sending notifications without any server dependency.  
  • This method is perfect for building quick notifications and alerts in your SharePoint solutions, especially when you want to keep things simple and inside the SPFx ecosystem. 

If you found this helpful, do not forget to share and comment! 

Transform your SharePoint list edit forms into Structured, user-friendly interfaces with JSON formatting, No code required!

Why Customize SharePoint Edit Form? 

SharePoint’s default edit form is functional but often lacks visual appeal and logical grouping, especially for lists with many fields. JSON form formatting empowers you to: 

  • Improve usability by organizing fields into collapsible sections. 
  • Enhance aesthetics with icons, headers, and consistent spacing. 
  • Add functionality like help links or dynamic buttons. 

In this guide, you will learn to customize the header, body and footer of the edit form popup using JSON let’s dive in! 

Step 1: Enable JSON Customization for Your List: 

  1. Navigate to your SharePoint list where you want to customize the edit form. 
  2. Click on the “Add new item” button. 
  3. In the form, click on the “Edit Form” option (top-right corner). 
  4. Easily customize your SharePoint list using JSON with a no-code, low-code approach to enhance layout and design.
  5. Select “Configure Layout” from the dropdown. 
  6. A panel will appear with three sections: Header, Body, Footer. 
  7. Choose the section you want to customize and paste your JSON code into the editor. 

Step 2: Structure of JSON form formatting: 

SharePoint Forms are divided into three sections: 

  1. Header: Modify the form header to display a title, icon or additional details 
  2. Body: Organize fields into sections for better readability 
  3. Footer: Customize the footer with buttons and actions. 

Step 3: Customizing the Header: 

The header appears at the top of the form. We can add: 

The header appears at the top of the form, and we can customize it to enhance the appearance by adding an icon, title, or even a custom logo. 

Adding an Icon in the header: 

{
  "elmType": "div",
  "attributes": {
    "class": "ms-borderColor-neutralTertiary"
  },
  "style": {
    "width": "100%",
    "border-top-width": "0px",
    "border-bottom-width": "1px",
    "border-left-width": "0px",
    "border-right-width": "0px",
    "border-style": "solid",
    "margin-bottom": "16px"
  },
  "children": [
    {
      "elmType": "div",
      "style": {
        "display": "flex",
        "box-sizing": "border-box",
        "align-items": "center"
      },
      "children": [
        {
          "elmType": "div",
          "attributes": {
            "iconName": "Onboarding",
            "class": "ms-fontSize-42 ms-fontWeight-regular ms-fontColor-themePrimary",
            "title": "Details"
          },
          "style": {
            "flex": "none",
            "padding": "0px",
            "padding-left": "0px",
            "height": "36px"
          }
        }
      ]
    },
    {
      "elmType": "div",
      "attributes": {
        "class": "ms-fontColor-neutralSecondary ms-fontWeight-bold ms-fontSize-24"
      },
      "style": {
        "box-sizing": "border-box",
        "width": "100%",
        "text-align": "left",
        "padding": "21px 12px",
        "overflow": "hidden"
      },
      "children": [
        {
          "elmType": "div",
          "txtContent": "= 'Employee Information of ' + [$Title]"
        }
      ]
    }
  ]
}

Where to make changes for popup form Appearance:

Change Required 

Modify This Part in JSON 

Change Icon 

"iconName": "Onboarding" (Replace with another Fluent UI icon) 

Change Icon Size 

“ms-fontsize-42" (increase/decrease number) 

Change Icon Color 

“ms-fontColor-themePrimary" (change theme color) 

Change Header Background Color 

Add “background-color” : “#F32F1” inside style 

Change Title Text 

Modify “txtContent”: “= 'Employee Information of  ' + [$Title]" 

Change Title Font Size 

“ms-fontSize-24" (increase/decrease number) 

Change Title Alignment 

“text-align”: “left” ->”center” or “right” 

Adjust Header Height & Spacing 

Modify “height”, “margin-bottom”, “padding” 

Customize the SharePoint Online list header by adding icons and styling it based on the list name to create an attractive and personalized look.

How to select an Icon for the Header: 

You can select any Fluent UI icon for your header. Follow these steps to get the correct icon name:  

  1. Go to https://uifabricicons.azurewebsites.net/ . 
  2. Search for the icon you want. 
  3. Right-click the icon and select “Copy Friendly Name”. 
  4. Paste the copied name into the “iconName” field in the JSON above. 

This will display the selected icon in your SharePoint form header. 

Adding a Custom logo in the header: 

If you want to display a custom logo instead of an icon, modify the JSON as follow: 

{
  "elmType": "img",
  "attributes": {
    "src": "https://yourtenant.sharepoint.com/sites/YourSite/Shared%20Documents
    /Logo.jpg",
    "title": "Company Logo",
    "class": "ms-borderRadius-circle"
  },
  "style": {
    "width": "200px",
    "height": "100px",
    "margin-right": "10px"
  }
}
Easily add a logo or image to the header of a SharePoint Online list to make it look better and match your brand.

Explanation of Changes: 

  • ElmType changed from “div” to “img” - this tells SharePoint to display an image instead of an icon. 
  • Src attribute- replace the placeholder URL with the actual URL of your logo stored in a SharePoint document library. 
  • Style changes- Adjust the width, height and margin as needed. 
  • Note:- Ensure that the image URL is publicly accessible or that SharePoint permissions allow users to view the image. 

Step 4: Customizing the Body into Sections:

{
  "sections": [
    {
      "displayname": "Personal Details",
      "fields": [
        "Title",
        "Address",
        "Email Address",
        "Date of Birth",
        "Contact Number",
        "Blood Group"
      ]
    },
    {
      "displayname": "Company Details",
      "fields": [
        "Previous Company Name",
        "Experience of Previous Company",
        "Total Number of Experience",
        "Designation in Previous Company",
        "Income of Previous Company",
        "Expected Income"
      ]
    }
  ]
}

Where to make changes to affect the popup form appearance: 

Change Required 

Modify This Part in JSON 

Change Section Heading 

Modify “displayname” : “Personal Deatils” or “displayname”: “Company Details” 

Add a New Section 

Copy a section and create a new “displayname” with relevant “fields” 

Add a Field to an Existing Section 

Add the field name to the “fields” array 

Remove a Field 

Delete the field name from the “fields” array 

Rearrange Fields in a Section 

Change the order of fields in the “fields” array 

Easily customize SharePoint list body content using JSON formatting to match your specific UI and functional requirements.

Step 5: Customizing the Footer with Action Buttons: 

{
  "elmType": "div",
  "style": {
    "width": "100%",
    "text-align": "left",
    "overflow": "hidden",
    "border-top-width": "1px"
  },
  "children": [
    {
      "elmType": "div",
      "style": {
        "width": "100%",
        "padding-top": "10px",
        "height": "24px"
      },
      "children": [
        {
          "elmType": "a",
          "txtContent": "='Contact Details for ' + [$Title]",
          "attributes": {
            "target": "_blank",
            "href": "https://www.google.com/",
            "class": "ms-fontColor-themePrimary
            ms-borderColor-themePrimary
            ms-fontWeight-semibold
            ms-fontSize-m
            ms-fontColor-neutralSecondary–hover
            ms-bgColor-themeLight–hover"
          }
        }
      ]
    }
  ]
}

Where to make changes for popup form Appearance:

Change Required 

Modification This Part in JSON

Change the Link URL 

Replace “href”: https://www.google.com/ with your desired link(e.g. [$ProfileURL] for dynamic links 

Open in Same Tab 

Change “target”: “_blank” to “target”: “_self”. 

Change Link Text 

Modify “txtContent”: “=’Contact Details for ‘ + [$Title]” 

Change Text Color 

Modify “class” and replace ms-fontColor-themePrimary with ms-fontColor-red. 

Make it a Button instead of a link 

Change “elmType” : “a” to “elmtype” : “button”  

Create a modern and attractive custom footer in SharePoint Online to elevate site design, improve navigation, and align with your organization's branding.

Step 6:  Testing and Debugging: 

  1. Copy the complete JSON code (header, body, and footer). 
  2. Paste it into the JSON customization panel in SharePoint. 
  3. Click Save and refresh your list. 
  4. Edit an item to see the customized popup form in action! 

Tips for Advanced Customization: 

  1. Conditional Formatting: Hide/show sections based on field values using “visible”: “=[$status]== ‘Active’” 
  2. Theming: Match your organization’s colors with “style”: { “background”: “#f0f0f0”} 
  3. Integrate Power Automate: Add buttons that trigger workflows using “actionType”: “executeFlow”. 

Conclusion:     

  • Customizing forms with JSON in SharePoint makes it much easier to create clean and user-friendly edit forms. You can organize fields better, add helpful icons, and customize buttons to make the form look good and work smoothly. This helps users save time and makes using the form more enjoyable.

Excel-Powered CRUD in SharePoint List using PnP JS and XLSX

Overview     Utilizing Excel as an information source, PnP JS for SharePoint operations, and the XLSX library for parsing Exceed expectatio...