Create a SharePoint App with React: Overview

Please NOTE: This blog series is currently a work in progress and subject to change.

This is part 1 in a series about creating a React App, using the Microsoft Toolkit and Ui-Fabric in SharePoint.


WebDev By The Bay is not affiliated with nor is this post endorsed by any company mentioned in this post. 

All opinions belong to the author of this post.

All Copyrights and Trademarks belong to their respective owners.

Full disclosure!

I am not a Software Engineer, I’m a Web Developer of almost 20 years. In my day job, for the past 6 years, I have been tasked with developing solutions in SharePoint.

This series is my journey in learning not only SharePoint but various other technologies.

Please Note: The only SharePoint App Model that Microsoft recommends is the SharePoint Framework aka. SPFx.

We will create some custom code but most of the code will be from the library examples to make learning the technology easier, at least for me.

This series is not about showing you how to code the various pieces but rather how you can piece the pieces together to make an application.

The basic setup of the React App is based on react-starter by Ted Pattison.

I will be adding how to use the PNPJS Library to surface SharePoint list data, modifying webpack.config and providing some tips on using the FluentUi.

There are several ways to use the Microsoft Graph, e.g. JavaScript SDK, Microsoft PNPJS library or the new Microsoft Toolkit, this project will use the PNPJS Library to surface the data in the backing SharePoint list.

App Purpose

Dashboard app to help manage Long Term Parking Requests and Approvals.


We will setup multi level approvals with Microsoft Power Automate.
This includes custom email notifications

There are several ways to develop apps for SharePoint. In this tutorial I will create a React app hosted in a SharePoint folder.

App Models

  • Provider Hosted App – No longer recommended
  • SharePoint Hosted App – No longer recommended
  • SharePoint Modern Page Web Parts developed with the SharePoint Framework (SPFX) – The only recommended model.

In my opinion, the SharePoint Framework is the way I would prefer to develop SharePoint solutions inside of SharePoint.

Microsoft has even stated that the SharePoint Framework is the only App Model that they guarantee not to be broken by SharePoint updates.

But here’s the catch, each of the App Models require your solutions be added to the SharePoint App Catalog. You or someone else will need to have tenant admin permissions in order to add any of the above models to the SharePoint App catalog.

I am a department developer and even though I am the admin of my departments SharePoint sites, I do not have tenant admin permissions. To have anything added to the app catalog could be a lengthy approvals process, this is understandable.

But the job still has to be done!

We could develop with Microsoft Power Apps but one thing to be aware of is that if your Power App is embedded in a normal html page and not a SharePoint Modern page, your Power App could at indeterminate times require the user to login again through the Microsoft login dialog. Power Apps will disregard the fact that the user is currently authenticated to SharePoint and or your Network.

Now this could be due to my employers network uses ADFS and there is no single sign on with Azure Active Directory just yet. Microsoft has provided a solution, Azure Active Directory Seamless Single Sign-On, but as far as I know this has not yet been implemented in my employers environment because my embedded Power Apps still require users to authenticate if the app has not been interacted with after a period time, even if the user is actively interacting with the page that contains my Power App.

This has been very discerning for several of my co-workers. Power Apps does not seem to be context aware, it does not recognize that my users network and SharePoint session are still valid and that the user is already authenticated with our company Network.

For a recent project, after much discussion with management, given the above restrictions, it was decided that I should develop the app as a React App and host it in a SharePoint folder.

This could also be due, and to me is more likely the reason is this is due to the PowerApp if embedded in an app that is served from a SharePoint folder is not in the scope of SharePoint.

Thanks goes to this great video by Ted Pattison for helping me get started.


To prevent the browser from caching your webpage, you might think that if you put something like

<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, min-fresh=1">

<!--Pragma is for older browsers like IE -->
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

in the header of your index page and this will prevent the browser from caching the content. When in fact it’s up to the browser whether or not to honor these settings, in my experience most of the time the Chrome browser ignores these settings. The official browser for our Enterprise is now Chrome.

Chrome will however, more often than not, surface the latest and greatest version of your content if your file name is different from the cached file.

This is one of my favorite techniques to ensure that my content is the latest and greatest.

I append a random, non repeating number to the filename. This is how I setup my webpack.config.js and I’m sorry, I do not remember where I learned this myself, but thank you.

const rand = Math.floor(Math.random() * 999999);

module.exports = {
    entry: ['@babel/poyfill', '.src/index.tsx'],
    output: { 
              filename: 'scripts/bundle'+rand+'.js',
              path: path.resolve(__dirname, 'dist'),

What happens if you don’t take the above steps? Your users may not see the latest and greatest changes due to the browser is surfacing the cached file and not the latest upload. At this point you may need to walk your users through the process of clearing the browser cache. Who wants to do that! The random filename above will eliminate this.

Setup Webpack

.html files hosted in SharePoint will not surface as an html page in your browser, instead the browser will try and download the file.

You will need to change .html file extensions to the .aspx extension before uploading to your SharePoint folder.

We can automate changing the file extension with webpack on each build!

If not already installed, make sure to install the plugin called html-webpack-plugin :
npm install html-webpack-plugin

Then in webpack.config.js create a const:

const HtmlWebpackPlugin = require(‘html-webpack-plugin’);

and change:

new HtmlWebpackPlugin({ template: path.join(__dirname, 'src', 'index.html')}),


new HtmlWebpackPlugin({ template: path.join(__dirname, 'src', 'index.html'), filename: "./index.aspx" }),

Now webpack will automatically save your index file with the .aspx file extension.


I chose to use the Microsoft Ui-Fabric Library to style this app.

If not already installed, in the same directory as project.json , on the cmd line execute npm install office-ui-fabric-react

Some things to be aware of with Ui-Fabric

Microsoft Ui-Fabric will dynamically assign style classes to the elements and these classes may or may not be different on each build. If you choose to override these classes, you cannot rely on these classes being the same name every time.

You can and I do use the declaration !important on some of the classes I override but this may or may not be ignored. This declaration is also unreliable unless you scope the classes, this may not be the right term but scope is how I refer to the following.

What do you mean, Scope a scss class?

First I prefer SASS, my css file has the extension .scss

I give each of the Ui-Fabric elements a custom class name but I still need to use default class names that are generated by the Ui-Fabric library, these would be classes that will not change such as ms-Button.

Why not just reference ms-Button or your custom style. In some scenarios, you need to detect if both classes are present and then apply your custom styles.

This is due to ms-Button is a Global style, changes would be applied across the entire app and this may or may not be what you intended.

HINT: To find out what your elements and classes are while the app is running. Shift+Ctrl+I or just right click the element on the page and select Inspect. Then find the element and take a look at the associated classes.

Ex: Ui-Fabric Button

1st build. Notice the default class root-133

<button type="button" id="mySubmitBtn" class="ms-Button ms-Button--action ms--command is-disabled root-133"></Button>

2nd build: Notice the default class root-133 might be different or it could stay the same. It could change to root-132. This is unreliable if you wish to override and apply your own styles.

What to do? A: Add a custom class name.

<button type="button" id="mySubmitBtn" class="ms-Button ms-Button--action ms--command is-disabled mySubmitBtn root-133"></Button>

mySubmitBtn is my custom class name.

Next in your scss file, check for not only the custom class mySubmitBtn but also check for the constant Ui-Fabric class(s).

Ex. {
// Submit button - Disabled State

     .ms-Button-icon {
       color: rgb(167,162,162) !important;
       font-size: 24px !important;

     // Submit Button label - Disabled State
     .ms-Button-label {
      color: rgb(162,162,162) !important;
      font-size: 24px !important;

Now your style will always be applied to only the specific elements where all classes, ms-Button ms-Button–action ms-Button–command is-disabled and mySubmitBtn classes are present.

Next – Part 2: Setup the app dependencies and basic layout


Video Series