Reading Time: 3 minutes
Update: I was mentioned during SharePoint Dev Weekly - Episode 61 – 26th of November 2019
If you want you can see the registration here :)

Update 2: During December, 19 2020 SharePoint Framework Community Call   I made a demo of my contribution, here you can find the registration :) 

Hi guys!
Today we’ll talk about a new SPFx sample webpart I made using SharePoint Framework

General needs

Usually, SharePoint sites are user-friendly, especially modern ones. Sometimes though, especially in the context of adoption a new site, like a new Modern Intranet, it is good to offer users the possibility of having a page guide, a tour, a tutorial, so that they do not feel lost like confused John Travolta

Nice new SharePoint Intranet!
But wait: where are my documents? And my tools?

To improve site adoption, you could create a video guide or well-explained documentation. However, some users do not have the time to read the documentation or to watch the video, they would just like to use the new site! For this type of end-users (most of them) you can create a dynamic tour while learning to use the new Intranet based on SharePoint Online.
There are lots of really cool plugin, using react too. I choose to use ReactTourJS.
Another package I decide to use is @pnp/spfx-property-controls a collection of reusable property pane controls for the SharePoint Framework solutions. In a particular way, I decided to try PropertyFieldCollectionData control

SPFx Tour WebPart in action!

Let’s look at how it works, applied to this really cool site The Landing taken from SharePoint look book sample!

When you start the tour, a modal will be displayed, with a description of the highlighted area, and you can go to the next step or go back, thus navigating inside the page.
The user will see the descriptions and will have the opportunity to preview the advice that the publisher thought for him.

SPFx Tour WebPart configuration

The WebPart property pane allows you to:

  • Choice the WebPart from a list of all WebParts on the current page
  • specify a descriptive text
  • specify the sorting, according to which it will be shown in the tutorial
  • enable or not the step within the tour

Code deep-dive

The solution is pushed in my GitHub repository, but I would like to focus on some snippets.

How to retrieve all SPFx WebPart in the current page

  public async GetAllWebpart(): Promise<any[]> {
    // page file
    const file = sp.web.getFileByServerRelativePath(;

    const page = await ClientSidePage.fromFile(file);

    const wpData: any[] = [];

   page.sections.forEach(section => {
      section.columns.forEach(column => {
        column.controls.forEach(control => {
          var wpName = {}
          var wp = {};
          //FIX: check if webPartData are available, in Text Webpart is undefined
          if ( != undefined) {
            wpName = `sec[${section.order}] col[${column.order}] - ${}`;
            wp = { text: wpName, key: };
          } else {
            wpName = `sec[${section.order}] col[${column.order}] - "Webpart"`;
            wp = { text: wpName, key: };


    return wpData;

How to customize @pnp/spfx-property-controls – PropertyFieldCollectionData with a textarea

                      id: "StepDescription",
                      title: "Step Description",
                      type: CustomCollectionFieldType.custom,
                      onCustomRender: (field, value, onUpdate, item, itemId) => {
                        return (
                          React.createElement("div", null,
                                style: { width: "600px", height: "100px" },
                                placeholder:"Step description",
                                key: itemId,
                                value: value,
                                onChange: (event: React.FormEvent<HTMLTextAreaElement>) => {
                                  onUpdate(, event.currentTarget.value);

To locate the WebPart, ReactTourJS needs a selector. I used data-sp-feature-instance-id data property associated with the WebPart instance id

  public static getTourSteps(settings: any[]): any[] {

    var result: any[] = new Array<any>();

    if (settings != undefined) {
      settings.forEach(ele => {
        if (ele.Enabled) {
              selector: '[data-sp-feature-instance-id=\'' + ele.WebPart + '\']',
              content: ele.StepDescription

    return result;

And it is all from my side 🙂

I hope you enjoy my new code contribution!

24 thoughts on “SharePoint modern page tutorial: an SPFX Tour sample WebPart”
  1. Hi Federico,

    Thanks for sharing the code, it’s great!

    Just a question, have you considered having the code run only once per user and storing whether a user has done the tour or not in local storage, so they don’t have to click through the tour each time? or is there some code that manages this in your repo?


    1. Hi Ross!
      Thanks for your comment! 🙂 It could be a nice improvement to manage users run (at least once), but it is not included in this version.
      This sample shows a basic approach to SharePoint adoption with a dynamic and configurable tour.
      Btw, cookie or local storage or list-based approach could be a solution in order to manage Tour execution from a specific user.

  2. I’ve installed this on a test site and am having issues getting it working. After dropping the webpart on a page I open the webpart properties and all the panel is greyed out and under the tour steps it has the “Loading Data…” spinner which never ends.

    Any suggestions?

    1. Hi David 🙂 thanks for your comment!
      Could you please give me others informations? Which browser did you use for testing ?
      Please consider this is a sample Webpart and it’s no bug free 🙂
      Would you like to DM me on twitter, so we can talk quickly if you need assistance, then we can come back here with solution?

        1. Hi Rick,
          just clone my repo from scratch and follow “Minimal Path to Awesome”

          restore dependencies: npm install
          build solution gulp build –ship
          bundle solution: gulp bundle –ship
          package solution: gulp package-solution –ship

          *Verify if there are errors or warnings in these phases*

          locate solution at .\sharepoint\solution\react-tour-pnpjs.sppkg
          upload it to your tenant app catalog
          add react-tour-pnpjs app to your site
          add react-tour-pnpjs webpart to your page to see it in action

          Based on my tests, It works with all browsers, in a new empty page (WebPart list in property pane is empty),and in a page with webparts.
          Could you please test in a new page, with no webparts, or with one simple webpart?
          It could be related with a specific webpart 🙂
          Did you check Console tab into Browser Developer Toolbar (F12)?
          Let me know if you find a specific error!

          1. Hi Rick,
            after our quick chat, I verified that there is a bug, I did not manage Text Webpart and I did not consider that Text Webpart object has control.webPartData prop undefined.
            The fix is available on my GitHub, just pull the latest version.
            Thanks for the nice conversation today, as shared in char, this is not a solution ready for the production environment, it is just a sample to show new features, new approaches for the community, btw today we learn that this WebPart has different object props 🙂

  3. Hi,
    Nice widget. Tried it works in IE but breaks in ie with errors
    Object doesn’t support property or method ‘find’
    Unable to get property ‘getBoundingClientRect’ of undefined or null reference


        1. Hi Syed,
          I test it with IE 11 (11.1130.17134.0) and it works, without polyfill-ie11 (original version from my Github).
          Please consider this is a sample WebPart and it’s no bug-free 🙂
          You can try to add IE 11 Polyfill package following those instructions,

          * run this command npm install –save @pnp/polyfill-ie11
          * use this import on TourWebPart.ts –> import “@pnp/polyfill-ie11”;

          Let me know 🙂

  4. Hi Federico,

    Thank you for the awesome web part. It is working fine in Chrome, Edge, but not in IE.
    I have tried Polyfill as you suggested, but no luck.

    * run this command npm install –save @pnp/polyfill-ie11
    * use this import on TourWebPart.ts –> import “@pnp/polyfill-ie11”;

    I have tested in Window 10 , IE 11 . Any thoughts?

      1. Hi Federico,

        I have tried in following IE versions with GitHub version and then adding Polyfill.

        IE 11 (11.1184.17134.0)
        IE 11 (11.592.18362.0)

        Getting following errors in console.
        SCRIPT438: Object doesn’t support property or method ‘find’
        tour-web-part_b13c8f2be70ff6da239b424f90e8a3aa.js (47,235554)

        SCRIPT5007: Unable to get property ‘getBoundingClientRect’ of undefined or null reference
        tour-web-part_b13c8f2be70ff6da239b424f90e8a3aa.js (47,240709)

  5. Hi Federico,

    Thank you for the great web part. Is it possible to include content in the header (e.g. Hub navigation) or footer? I would love to be able to highlight these aspects to new users in the tour.

    1. Hi Federico,

      I have the same question as @DJ,

      Is it possible to include content in the header (e.g. Hub navigation) or footer? I would love to be able to highlight these aspects to new users in the tour.


  6. Hi,
    Can you please upload the react tour package as i am finding it difficult to package it


  7. Hi Federico,

    Thanks for sharing the code.
    I am getting node modules issue while installing NPM. Could you please share the Node version , NPM version and Gulp version so that issue may be fixed to me.

    1. Hi Federico,

      I have fixed node module issue. But getting two errors while configuring web titles showing duplicate and not able to add position.

      Could you please help me on it.

Leave a Reply

Your email address will not be published. Required fields are marked *