Single Page App In SharePoint Using React

In this article, I will be covering the steps to create a Single Page Application (SPA) in Sharepoint using ReactJS.

Introduction

 
I would like to begin with a detailed introduction and the motivation for initiating this article. You can skip this entire part of the article and jump directly to Part 2 where I have given the actual steps for creating the Single Page Apps in SharePoint.

It is well known among the SharePoint community that SharePoint Framework (SPFx) has emerged as the most popular development method in recent times. One of the requirements from the SharePoint Developers community was to enable SharePoint developers with the easy creation of SPAs. The SPFx method provided that hope as there was a plan by Microsoft to approach the SPFx in a phased manner and include the SPA module after the Client-side web part module is stabilized.

In the latest version of SPFx, there is an option to convert the existing web parts to single part app pages (SPAP). Now, I am not sure if this is Microsoft’s version of SPAs in SharePoint or if there is any plan to include SPA module in SPFx in the future.

SPAPs are the extensions of Client-side Web Parts. These types of pages basically allow just one web part on a page and restrict the developers or power users from adding multiple web parts to the page.

The overall development experience is exactly similar to the client-side web parts development method using SPFx. Developers should first create the client-side web part using the SPFx method and then follow a few additional steps to convert the existing page to single part app page (SPAP) using either PowerShell script or by running a JS script as explained in the official documentation here.

If you look from the developer’s perspective, below mentioned are the high-level steps to create SPAPs.

  1. Create a new client-side web part using SPFx development method. Click Here for detailed steps from Microsoft's official documentation.
  2. After deploying this web part, you need to add it to the SharePoint page. Click Here for the steps to add web parts to modern SharePoint pages.
  3. Now, you can convert this page as a single page app part (SPAP). Click Here to refer to the steps to convert the page to single part app page(SPAP).

In my opinion, the single page app page (SPAP) is definitely not a Single Page App (SPA) and hence I am writing this article which will help you to create an SPA from within SharePoint using NodeJS based development.

Motivation for this Article Series

 
We, the SharePoint Developers, have seen numerous development methods starting from the farm-based solutions to the latest offering of SPFx. However, we have always been confined by the rules set forth by the development models. The SPFx method provides much-needed liberty and development experience.

Many people may not be aware that SPFx is derived from the same principle of NodeJS based open source development. In fact, much before the SPFx was officially announced, there were a few demos and documentation conducted and written by Microsoft about how NodeJS development method can be leveraged. This was a preparatory measure in order to prepare the developers for the SPFx.

In this article series, I will provide the steps to develop a Single Page Application using the node.js based development method which communicates with SharePoint resources using REST APIs and perform desired activities.

Prerequisites

 
This article is not an extensive guide for all the technologies used to develop the SPA. Mentioned below are some of the good-to-have and non-mandatory prerequisites which will help you to understand and adopt this method quickly.
  • Reader has knowledge of SPFx (Not mandatory though)
  • Reader has some knowledge of Open source development using Node.js and has already installed all the relevant packages such as (NodeJS, npm, webpack etc.)
  • Reader has some understanding of advanced JS, TypeScript, and ReactJS
  • Reader is aware of the existence of JS bundler libraries such as webpack, gulp etc
  • SharePoint Online development environment setup is already available

This Article series is divided into three major parts as mentioned below.

  • Part 1: Introduction & Motivation (This article)
  • Part 2: Getting Started
    • Basic setup
    • How to open a SharePoint page and connect to Node.JS development environment
  • Part 3: Simple Sharepoint SPA with an example
    • SPA Layout using CSS grid
    • Display of SP lists in Side Nav and content in the Main section

Note: Please be informed that this method is not an officially recommended method by Microsoft, please proceed to use this as per your judgment and business use case.

The previous part of this article is all about the introduction and the motivation for starting this article series, in this article onwards we will start with the actual steps to develop a Single Page App in SharePoint using ReactJS wired up with TypeScript.
 

Preparation using Node JS command line utility

Step 1

Open the NodeJS command window and then make sure to install the create-react-app utility
 
npm install -g create-react-app

Step 2

Create a new project with the name of your choice, let’s say sp-app
 
create-react-app sp-app --scripts-version=react-scripts-ts

Please note above that “--scripts-version=react-scripts-ts” is included to add the typescript flavor to the react JS.

The reason for including typescript mix is to ensure that we are in alignment with Microsoft’s SPFx development setup requirements so that it is easy for developers to move whole solution or modules to the SPFx and convert as a Client Side Web Part.

Step 3

Now, we are ready with the initial setup of the NodeJS for the development, you can now run the commands below to start the app.
  1. cd sp-app
  2. npm start
Once the above command is executed you can now open the browser with the URLhttp://localhost:3000/ and verify if the app is running as expected.

Step 4

Run the below pnp.js command to bring SharePoint REST APIs equation into the context.
 
npm install @pnp/logging @pnp/common @pnp/odata @pnp/sp --save

Preparation on SharePoint Designer

Assuming that you already have a SharePoint site for development and testing purposes, open the site using the SharePoint designer and then follow the steps below to create an initial page.

Once you open any site in the SharePoint Designer, you will notice all the resources listed under side navigation.

  • Here, you can click on Site Pages library.
  • Once you click on the Site Pages library, you will notice a “Page” button on the top ribbon bar as shown in the picture below.
  • Now, you can click on the Page > ASPX, and then rename the file thus created to your convenient name. In this example below, I have created it as index.aspx.

    Single Page App In SharePoint

  • Now, you can open this page by right-clicking on the file and then “Edit File in Advanced Mode".
Single Page App In SharePoint

Now, you can copy and paste the below snippet to the index.aspx page in the SP Designer

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><%@ Page Language="C#" %><%@ Register tagprefix="SharePoint" namespace="Microsoft.SharePoint.WebControls" assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>  
  2. <html dir="ltr"  
  3.     xmlns="http://www.w3.org/1999/xhtml"  
  4.     xmlns:mso="urn:schemas-microsoft-com:office:office"  
  5.     xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882">  
  6.     <head runat="server">  
  7.         <meta name="WebPartPageExpansion" content="full" />  
  8.         <meta http-equiv="X-UA-Compatible" content="IE=10" />  
  9.         <SharePoint:CssRegistration Name="default" runat="server"/>  
  10.         <title>SharePoint SPA</title>  
  11.     </head>  
  12.     <body>  
  13.         <div class="ms-Grid-row" id="root"></div>  
  14.     </body>  
  15.     <!-- Dependencies -->  
  16.     <script type="text/javascript" src="http://localhost:3000/static/js/bundle.js"></script>  
  17. </html>  

When you open this SharePoint page from the browser, you should be able to see the page similar to below.

Single Page App In SharePoint
 
Don’t worry about the missing logo image on the page. In the next section, we will get into real development, Initial setup and connecting to SharePoint through pnp.js library.

Now, you can open this project on any IDE of your choice, I am using the Visual Studio Code for the demo purpose. Your folder structure should look like the below image.

Single Page App In SharePoint
 
Open the App.tsx file and then replace the code with the code below.
  1. import * as React from 'react';  
  2. import {  
  3.     Web  
  4. } from '@pnp/sp';  
  5. class App extends React.Component < any, any > {  
  6.         constructor(props: any) {  
  7.             super(props);  
  8.             this.state = {  
  9.                 lists: []  
  10.             };  
  11.         }  
  12.         componentWillMount() {  
  13.             const web = new Web(“Enter your Web URL as a string”)  
  14.             const lists: any = [];  
  15.             web.lists.get().then(Alllists => {  
  16.                 Alllists.forEach(function(list, index) {  
  17.                     lists.push({  
  18.                         key: index,  
  19.                         title: list.Title  
  20.                     });  
  21.                 })  
  22.                 this.setState({  
  23.                     lists: lists  
  24.                 })  
  25.             })  
  26.         }  
  27.         public render() {  
  28.             return ( < div > {  
  29.                     this.state.lists.map(list => < div > {  
  30.                         list.title  
  31.                     } < /div>)} < /div>);  
  32.                 }  
  33.             }  
  34.             exportdefault App;  

Now, let us understand what we have written in the code snippet above.

This is a React JS component in which

  • We are importing the @pnp/sp library into our application and then we are accessing the “Web” object.
  • We are then creating an instance of the “Web” object
  • Then using the lists method of the Web method, we are fetching all the lists within the site in the context
  • Then we are displaying all the lists through the render method of the ReactJS

Now, save the file “App.tsx” file and the application will compile again. If the execution was stopped then you can run “npm start” command again to run the application.

Now, when you open the index.aspx file that you have created earlier in the “Site Pages” library within your SharePoint site, you should be able to see all the lists of the SharePoint site as shown in the image below.
 
Single Page App In SharePoint
 
The major objective of this part of the article was to do the initial setup and then establish the connectivity with the SharePoint using pnpjs library.

In the next section, we will discuss about various options available to create a SPA layout.

Part 3 : Simple SharePoint SPA with Example

In this section, we will go through the steps below.

  • Create SPA layout using CSS Grid
  • Create a simple React component which fetches all the lists from the SharePoint site within the selected context and will arrange them in the Left Navigation section.
  • Clicking on the list name will display the records with title and IDs in the main section.

Create SPA layout using CSS Grid

 
Single Page Applications will typically consist of five sections as mentioned i.e. Header, LeftNavigation, Main Content, Right Navigation and then the footer. The challenge always had been to create a layout which is responsive in nature. Fortunately, there are plenty of options available now. In this example, I am using the CSS grid .
 
In the IDE open the file App.css file and then replace the existing content with the css mark up as mentioned in the snippet below.
  1. .header { grid-area: header; }    
  2. .leftnav { grid-area: menu; }    
  3. .main { grid-area: main; }    
  4. .rightnav { grid-area: right; }    
  5. .footer { grid-area: footer; }    
  6.     
  7. .grid-container {    
  8.   display: grid;    
  9.   grid-template-areas:    
  10.     'header header header header header header'    
  11.     'menu main main main main right'    
  12.     'menu footer footer footer footer footer';    
  13.   grid-template-columns: 200px 1fr 1fr 1fr 200px;    
  14.   grid-template-rows:  50px 1fr auto;    
  15.   grid-gap: 10px;    
  16.   background-color#2196F3;    
  17.   padding10px;    
  18.   min-height100vh;    
  19. }    
  20.     
  21. .grid-container > div {    
  22.   background-color: rgba(2552552550.8);    
  23.   text-aligncenter;    
  24.   padding20px 0;    
  25.   font-size20px;    
  26. }    
Note
Explanation about how this works is out of scope of this article, Please refer to some of the CSS grid training materials

Now, the next step is to make the adjustment in the App component. In order to do this open the App.tsx file and then replace the existing content with the below code snippet. 

  1. import * as React from 'react';  
  2. import './App.css';  
  3. import {  
  4.     Web  
  5. } from '@pnp/sp';  
  6. const web = new Web("https://yourtenant.sharepoint.com/sites/dev/");  
  7. class App extends React.Component < any, any > {  
  8.     constructor(props: any) {  
  9.         super(props);  
  10.         this.state = {  
  11.             lists: [],  
  12.             listItems: []  
  13.         };  
  14.         this._onClickHandler = this._onClickHandler.bind(this);  
  15.     }  
  16.     async _onClickHandler(e: React.MouseEvent < HTMLElement > ) {  
  17.         var listName = e.currentTarget.innerText;  
  18.         var lstResults = [{}];  
  19.         const result = await web.lists.getByTitle(listName).items.get();  
  20.         for (var i = 0; i < result.length; i++) {  
  21.             lstResults.push({  
  22.                 key: i,  
  23.                 ID: result[i].Id,  
  24.                 Title: result[i].Title  
  25.             })  
  26.         }  
  27.         this.setState({  
  28.             listItems: lstResults  
  29.         });  
  30.     }  
  31.     componentWillMount() {  
  32.         const lists: any = [];  
  33.         web.lists.get().then(Alllists => {  
  34.             Alllists.forEach(function(list, index) {  
  35.                 lists.push({  
  36.                     key: index,  
  37.                     title: list.Title  
  38.                 });  
  39.             })  
  40.             this.setState({  
  41.                 lists: lists  
  42.             })  
  43.         })  
  44.     }  
  45.  public render() {  
  46. return (  
  47.   
  48.         <div className="grid-container">  
  49.             <div className="header">Header</div>  
  50.             <div className="leftnav" style={{ textAlign: "left", paddingLeft: "10px" }} >  
  51. {this.state.lists.map(list =>  
  52.                 <div >  
  53.                     <a href="#" onClick={this._onClickHandler}>{list.title}</a>  
  54.                 </div>)}  
  55.   
  56.             </div>  
  57.             <div className="main">  
  58. {(this.state.listItems.length === 0) ? 'No Data' :  
  59.   
  60.                 <table>  
  61.                     <tbody>  
  62.                         <tr>  
  63.                             <th>Title</th>  
  64.                             <th>ID</th>  
  65.                         </tr> {this.state.listItems.map(lstitems =>  
  66.                         <tr>  
  67.                             <td> {lstitems.ID} </td>  
  68.                             <td> {lstitems.Title} </td>  
  69.                         </tr>)}  
  70.   
  71.                     </tbody>  
  72.                 </table>}  
  73.   
  74.             </div>  
  75.             <div className="rightnav">Right</div>  
  76.             <div className="footer">Footer</div>  
  77.         </div>  
  78. );  
  79. }  
  80. }  
  81. export default App;  

Since this is not an article about the React JS or CSS Grid, I am not explaining the details about how the code works here. I will be looking forward to comments, If you need any explanation I will be happy to add that here. Please note that this example has a very basic setup in terms of css and the coding.

Now, after saving both the files you can now run a command "npm start" again and then open the index.aspx file from SharePoint. Now, you should be able to see the page as shown in the image below.

Single Page App In SharePoint

This is a simple example which sets up the initial template. As you can notice, you can click on the name of any list in the left navigation section and the page will immediately fetch all the records of the selected list and then displays the title and ID in the main section in a tabular format without refreshing the page.

Mentioned below are a few of the noticeable references while preparing this article.

Issues

You may encounter a few issues when you follow the steps above. Please perform the below-mentioned adjustment to a couple of files before hitting npm start command.

open the tslint.js file from the root folder and then make adjustment as shown below 

  1. {  
  2.   "extends": [],  
  3.   "defaultSeverity""warning",  
  4.   "linterOptions": {  
  5.     "exclude": [  
  6.       "config/**/*.js",  
  7.       "node_modules/**/*.ts",  
  8.       "coverage/lcov-report/*.js"  
  9.     ]  
  10.   }  
  11. }  

Open the tsconfig.json file under root folder and then add below line under the compiler option

  1. "skipLibCheck"true  
I have also created a git repository with this starter code, you can download or clone this starter kit from here and follow the instructions provided there to execute the project.