Aiming for a safer Content Editor Web Part

In classic SharePoint, the Content Editor Web Part (CEWP) was that magical tool that would turn a regular user into a Citizen Developer. SharePoint pages are collections of components, and the CEWP was the universal plug that could bring any widget to our page.

Its sibling, the Script Editor Web Part (SEWP), had a similar role. For the record, I have never come across a situation where the SEWP was more valuable to me than the CEWP. Their cousin, the Page Viewer Web Part, also offered similar capabilities, but that’s a slightly different story.

The convenience of CEWP and SEWP came at a price: there were no safeguards, and they would allow any JavaScript snippet to run in a SharePoint page. That security hole was Microsoft’s argument for taking them out of modern SharePoint.

Modern SharePoint doesn’t offer a CEWP or SEWP out of the box, but they can be re-created using the SharePoint Framework (SPFx). A web search for “modern Content Editor Web Part” will bring a few options. Let me just highlight two of them: the PnP React Script Editor Web Part, by Mikael Swanson, and my own Dangerous Content Web Part I published in 2020.

Why “Dangerous”? Because those SPFx solutions take us back to square one, where any script can run in the page. I wanted to make that clear, hence the name (inspired by the React method dangerouslySetInnerHTML).

How can we improve the situation?

My initial thought was to use a sanitizer. Interestingly, this idea is also making its way in the web specs, currently at an experimental stage. The research I did when I worked on a “Safe Content Web Part” led me to a number of sanitizing solutions, but also to the conclusion that there was no foolproof one, because client-side scripting offers so many possible angles of attack.

Fast forward to 2022, I was browsing the PnP issues and came across an idea submitted by mikezimm: restrict code to only approved snippets, stored in approved repositories. A governance approach instead of a technical approach. That sounded great to me, and I took that direction. That’s how the Cherry-Picked Content Web Part was born, as a spin-off of the Dangerous Content Web Part.

The Cherry-Picked Content Web Part is a rich sample. Not only does it provide the web part, it also includes 16 “sub-samples”, from video widget to charting and inclusion of the powerful Microsoft Graph Toolkit. I actually took the CEWP concept a step further, enabling the snippet to leverage the context of the web part.

Give it a try, and if you have other snippet suggestions feel free to post them here! A snippet can be embedded in two ways:

  • Isolated: the code snippet is executed in an iframe, to avoid interferences between the page and the snippet. Note that the snippet can still interact with the page.
  • Inline: the code snippet runs directly in the page.

In both configurations, malicious code could still be executed on the page. It is the responsibility of the publishers – users who are granted edit access to the approved libraries – to ensure that the code is safe.

Not interested in a CEWP replacement? The sample still offers some interesting concepts:

  • Cascading dropdown and conditional display in the Property Pane
  • Use of SPHttpClient and the SharePoint REST API
  • React function component with useState and useEffect hooks
  • React Portal in combination with an iframe
  • Various examples of client-side code in the samples: Microsoft Graph (teams), Microsoft Graph Toolkit (people, email, agenda), charts (Chart.js, Chartist), widgets (map, stock, countdown, clock, video, game), SharePoint SOAP and REST APIs.

A refresh for the tiniest SharePoint SOAP library

Audience: SharePoint geeks

An Easter egg in the multiple SharePoint-related solutions I released in the past 3 months: a rewrite of my tiny pocketSOAP library. If you are familiar with SPServices, pocketSOAP is a hundred times smaller while covering more SOAP calls. Plus, it doesn’t depend on jQuery! Of course, it doesn’t include all the bells and whistles that made SPServices so appealing for real-life scenarios, and is certainly not as performant. pocketSOAP is more of a “code golf” exercise. In these days of PnPjs and Microsoft Graph, I am not even sure if SOAP has any relevance anymore (although Jeff Teper mentioned in a recent meetup that the modern frameworks still don’t offer a 100% coverage of legacy features). For SharePoint geeks only 😊

Anyway, you’ll find the full, modern pocketSOAP code on PnP among those Github samples. Modern means that in 2022 we don’t need to support Internet Explorer or legacy Edge anymore in Microsoft 365, and that removed some more fat from the library. For the record, the samples are actually “sub-samples” and part of the Cherry-Picked Content Web Part solution, more on that in a couple days!

Here is a example of how to use pocketSOAP in your JavaScript code:

Introducing the Property Pane Portal [Part 3]

Audience: SPFx Reactjs developers.

[Part 1] Rethinking the SPFx Property Pane controls

[Part 2] Sample 1: Fluent UI controls

[Part 3] (this post) Sample 2: PnP SPFx Controls

[Part 4] The concept: leveraging Reactjs Portal for SPFx

[Part 5] Diving into the code

[Part 6] Sample 3: Microsoft Graph Toolkit controls

In part 2, I showcased the use of Fluent UI controls in the Property Pane. Now it’s the turn of the PnP SPFx Controls.

Today, the PnP portal on Github offers two sets of Reactjs controls for your SPFx solution:

These libraries are extremely useful, because they are targeted at Microsoft 365 users and offer controls that you wouldn’t get out-of-the-box in other control libraries, not even with Microsoft’s own Fluent UI. For example: SharePoint list picker, list item picker, or people picker. The only library I can think of that comes close is the Microsoft Graph Toolkit, which we’ll tackle in part 6 of this series.

Listen to Joel Rodrigues introducing the SPFx Reactjs Controls, starting at 26:15 in the August 2 episode of the Microsoft 365 Developer Podcast.

Now, the painful part is that you need two libraries, because the Property Pane cannot use the regular controls and requires its own dedicated property controls. This is what we intend to change with the Property Pane Portal: use the same sp-dev-fx-controls-react library not just for the Web Part body, but also for the Property Pane!

The general steps are the same as in part 2, with the use of PropertyPaneHost and PropertyPanePortal. The only difference is the control itself:

Note how the context gets passed to the components through a Reactjs Context Hook. Here again, just like for the example in part 2, the Property Pane Portal allows us to leverage all the usual Reactjs patterns. The benefit is not just to skip the sp-dev-fx-property-controls library, but also pave the way to richer forms allowing more dynamic styling or interaction across components.

See it for yourself with the Github sample. A sppkg package (for demo purposes only) is included if you are in a hurry 🙂

Introducing the Property Pane Portal [Part 2]

Audience: SPFx Reactjs developers.

[Part 1] Rethinking the SPFx Property Pane controls

[Part 2] (this post) Sample 1: Fluent UI controls

[Part 3] Sample 2: PnP SPFx Controls

[Part 4] The concept: leveraging Reactjs Portal for SPFx

[Part 5] Diving into the code

[Part 6] Sample 3: Microsoft Graph Toolkit controls

In part 1, I explained the objective of the Property Pane Portal: allow us to use any Reactjs controls library in the Property Pane. This post showcases the concept applied to the Microsoft Fluent UI Northstar controls. Here is a screenshot of the expected result for our Github sample:

To follow this post, a prerequisite is to be familiar with SPFx Reactjs and the default SPFx Property Pane. If you are only interested to test drive the Web Part, you can grab the sample sppkg file (demo purposes only) from Github.

In the Property Pane, each default control (text field in the example below) is generated by a built-in function (PropertyPaneTextField() in the example).

Let’s now see how the code in our Fluent UI Github sample differs.

With the Property Pane Portal technique, the generic function PropertyPaneHost() only generates the host of each control:

The Web Part property propertyPaneHosts serves as data store for the location of the hosts. It is attached to the Web Part (“this”) to ensure there is no collision, for example in case a page hosts multiple instances of the same SPFx Web Part.

The controls themselves are included in the React DOM, along with the regular components used in the Web Part body (screenshot below). Then the job of the Reactjs Portal is to beam them to the Property Pane.

You’ll find the CustomPropertyPane component in CustomPropertyPane.tsx:

The machinery that supports the PropertyPanePortal component and the propertyPaneHost function is hosted in the PPP folder, and should work with any Reactjs controls library. Parts 4 and 5 will explore the concept and code in more details. In the meantime, feel free to post questions in the comments below.

Introducing the Property Pane Portal [Part 1]

Audience: SPFx Reactjs developers.

My quest for an easier way to build and maintain Property Pane controls on the SharePoint Framework.

[Part 1] (this post) Rethinking the SPFx Property Pane controls

[Part 2] Sample 1: Fluent UI controls

[Part 3] Sample 2: PnP SPFx Controls

[Part 4] The concept: leveraging Reactjs Portal for SPFx

[Part 5] Diving into the code

[Part 6] Sample 3: Microsoft Graph Toolkit controls

A long due post…

Last year, I started doing more serious development work with the SharePoint Framework (SPFx).

I have been using JavaScript for 15 years, and got started with Reactjs in 2019, directly working with function components and hooks – rather than the traditional class components – as primary building blocks. My first Reactjs solutions were built on the Create React App toolchain. Transitioning to SPFx was easy, until I started building custom Property Pane forms. While the body of a SPFx Web Part behaves like any single page application, the Property Pane follows a very specific format. Let’s take a closer look.

Below an example of Property Pane taken from the Microsoft documentation. On the surface, it looks like a Web form allowing to set the Web Part properties.

When we crack the code open however, it doesn’t look like a regular client side form:

groupFields: [
PropertyPaneTextField('list', {
label: 'Select a list'
PropertyPaneCheckbox('display', {
label: 'Display'
PropertyPaneSlider('max', {
label: 'Max number of tasks'

(note: simplified code for illustration purposes only)

The controls are encapsulated in predefined functions. In a way, it’s as if each control was its own form.

It’s all fine, and even convenient, as long as stay within the boundaries of what the functions allow. But it falls short as soon as we require a little more advanced functionality, such as dynamic choices, conditional formatting, etc. For example, you might want to let the user pick a site, or a group, or a list item, and the available choices will naturally depend on the context.

SPFx has an answer to that: it allows us to build our own custom controls. The process however is very intricated, and needs to be followed for every custom control. If for example you wanted to leverage the Fluent UI controls in the Property Pane, you would have to maintain for each control a dedicated Property Pane version. In comparison, in the Web Part body, you would be able to use the Fluent UI library as is.

Such an approach is actually available in the PnP community. I had some opportunities to be involved in the testing of the library, and have discussions with some of its main developers (Alex Terentiev, Elio Struyf, Joel Rodrigues). Same deal, the team needs to maintain two instances in parallel: the regular Reactjs controls and the dedicated Property Pane controls.

When I started diving into the SPFx tutorial, I found out that each of these custom controls is made of two layers (diagram below): a base that anchors the control to the Property Pane, and then the core control itself that handles the user interface and functionality. The base gets in place first, then calls an onRender() method to summon the control. Each control includes an update() method to push changes back to the Web Part property bag.

This got me thinking. Could we in some way avoid the redundancy? And as a bonus, directly hook a regular Reactjs component in here? That’s what I pictured in the diagram below: a generic, reusable frame that could serve as host to any Reactjs control.

It took me a couple days to come up with a workable model (the “Property Pane Portal”), weeks to test it, and then months to start writing about it 😊. In the next episodes, I’ll share some samples of the PPP in action, and I’ll provide more details on the architecture and the code that supports it. The key ingredient is Reactjs Portals, which allow to beam an element to another part of the DOM.